From e45395bbdf6bc16a112930361856a1f786c8e835 Mon Sep 17 00:00:00 2001 From: CismonX Date: Sat, 30 Oct 2021 22:43:54 +0800 Subject: [PATCH] Refactor code. --- .gitignore | 3 + INSTALL.md | 50 +++-- Makefile.am | 2 + README.md | 35 ++-- configure.ac | 41 ++-- examples/Makefile.am | 9 +- examples/sixdraw.c | 86 +++++--- include/ctlseqs.h | 411 ++++++++++++++++++++++++++------------ src/Makefile.am | 9 +- src/ctlseqs.c | 384 ++++++++++++++++++++++------------- tests/Makefile.am | 10 +- tests/ctlseqs/match.exp | 19 +- tests/ctlseqs/partial.exp | 5 +- tests/init.exp | 4 +- tests/tcsgrep.c | 204 ++++++++++--------- 15 files changed, 797 insertions(+), 475 deletions(-) diff --git a/.gitignore b/.gitignore index 09ca6b4..5311ba1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,8 +25,10 @@ autoscan.log compile config.* configure +configure~ configure.scan install-sh +m4/ Makefile Makefile.in missing @@ -37,4 +39,5 @@ stamp-h1 # build *.o +build/ ctlseqs-*.tar.gz diff --git a/INSTALL.md b/INSTALL.md index 2e1dbc1..84c006e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,38 +1,36 @@ -# Installing ctlseqs +Installing ctlseqs +================== -## Copy Code to Your Project + Copy Code to Your Project + ------------------------- -The code of ctlseqs is simple, and can be used out-of-the-box. Just copy -[ctlseqs.h](include/ctlseqs.h) and [ctlseqs.c](src/ctlseqs.c) to your project -and build it alongside with other code. + The code of ctlseqs is simple, and can be used out-of-the-box. Just copy + ctlseqs.h and ctlseqs.c to your project and build it with other code. -Requires an ISO C99 and POSIX.1-2001 compliant C implementation. + Requires an ISO C99 and POSIX.1-2001 compliant C implementation. -## Build and Install From Source + Build and Install From Source + ----------------------------- -Alternatively, ctlseqs can be built into a shared/static library with -GNU Autotools (Autoconf, Automake, Libtool and Autoconf Archive). + Alternatively, ctlseqs can be built into a shared/static library with + GNU Autotools (Autoconf, Automake, Libtool and Autoconf Archive). -```shell -autoreconf --install -./configure -make -``` + autoreconf --install + ./configure + make -Optionally, you can run tests (requires DejaGnu) and install the library. + Optionally, you can run tests (requires DejaGnu) and install the library. -```shell -make check -make install -``` + make check + make install -Unix man pages are not automatically installed with `make install`, and should -be installed manually with `make install-man`. + Unix man pages are not automatically installed with `make install`, and + should be installed manually with `make install-man`. diff --git a/Makefile.am b/Makefile.am index 0801f07..77393ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,4 +6,6 @@ # this notice are preserved. This file is offered as-is, without any warranty. # +ACLOCAL_AMFLAGS = -I m4 + SUBDIRS = include src doc man tests examples diff --git a/README.md b/README.md index 486c068..b7e5fbb 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,28 @@ -# ctlseqs +ctlseqs +======= -[![Build Status](https://shields.io/drone/build/CismonX/ctlseqs?server=https%3A%2F%2Fdrone.cismon.net)](https://drone.cismon.net/CismonX/ctlseqs) -[![License](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](COPYING) -[![Savannah](https://img.shields.io/badge/hosted_on-Savannah-pink)](https://sv.gnu.org/p/ctlseqs) + The ctlseqs library provides C API for handling ECMA-35/ECMA-48 compatible + control functions, which is commonly used for communication between terminal + emulators and text-based programs. -## About + ctlseqs is free software, licensed under the terms of the GNU General Public + License, either version 3, or any later version of the license. See COPYING + for details. -The ctlseqs library provides C API for handling ECMA-35/ECMA-48 compatible control functions, -which is commonly used for communication between terminal emulators and text-based programs. + See INSTALL.md for instructions on how to build and install ctlseqs. -## Getting Started + Visit the [project homepage] for documentation, mailing lists, releases, + and everything else about ctlseqs. -For installation instructions, see [INSTALL.md](INSTALL.md). -Documentation of the library can be read [online](https://nongnu.org/ctlseqs/manual), or read with `info ctlseqs` after installation. -Unix man pages are also available. + + +[project homepage]: https://savannah.nongnu.org/projects/ctlseqs diff --git a/configure.ac b/configure.ac index 7af5372..8f36580 100644 --- a/configure.ac +++ b/configure.ac @@ -1,24 +1,25 @@ dnl dnl Copyright (C) 2020,2021 CismonX dnl -dnl Copying and distribution of this file, with or without modification, are -dnl permitted in any medium without royalty, provided the copyright notice and -dnl this notice are preserved. This file is offered as-is, without any warranty. +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty, +dnl provided the copyright notice and this notice are preserved. +dnl This file is offered as-is, without any warranty. dnl -AC_PREREQ([2.60]) +AC_PREREQ([2.69]) AC_INIT([ctlseqs], [0.1.0], [bug-report@cismon.net]) AC_CONFIG_SRCDIR([src/ctlseqs.c]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([foreign info-in-builddir]) AM_EXTRA_RECURSIVE_TARGETS([install-man uninstall-man]) -LT_PREREQ([2.4.0]) +LT_PREREQ([2.4.2]) LT_INIT # Checks for programs. -AC_PROG_CC_C99 -AC_PROG_CXX AC_PROG_AWK +AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S @@ -28,12 +29,14 @@ AC_PROG_MAKE_SET m4_ifdef([AX_GCC_BUILTIN], [ AX_GCC_BUILTIN(__builtin_expect) AX_GCC_BUILTIN(__builtin_unreachable) +]) +m4_ifdef([AX_GCC_FUNC_ATTRIBUTE], [ AX_GCC_FUNC_ATTRIBUTE(cold) AX_GCC_FUNC_ATTRIBUTE(hot) ]) # Checks for header files. -AC_CHECK_HEADERS([fcntl.h limits.h stddef.h stdlib.h string.h sys/ioctl.h termios.h unistd.h]) +AC_CHECK_HEADERS([fcntl.h sys/ioctl.h termios.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL @@ -42,13 +45,23 @@ AC_TYPE_SIZE_T AC_TYPE_SSIZE_T # Checks for library functions. -AC_CHECK_FUNCS([memset strtoul]) +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([strtol strtoul tcgetattr tcsetattr ioctl]) # Specify libtool library version. -m4_define([CTLSEQS_LT_CURRENT], [0]) -m4_define([CTLSEQS_LT_REVISION], [0]) +m4_define([CTLSEQS_LT_CUR], [0]) +m4_define([CTLSEQS_LT_REV], [0]) m4_define([CTLSEQS_LT_AGE], [0]) -AC_SUBST([CTLSEQS_LT_VERSION], [CTLSEQS_LT_CURRENT:CTLSEQS_LT_REVISION:CTLSEQS_LT_AGE]) +AC_SUBST([CTLSEQS_LT_VERSION], [CTLSEQS_LT_CUR:CTLSEQS_LT_REV:CTLSEQS_LT_AGE]) -AC_CONFIG_FILES([Makefile include/Makefile doc/Makefile man/Makefile src/Makefile tests/Makefile examples/Makefile]) +AC_CONFIG_FILES([ + Makefile + include/Makefile + doc/Makefile + man/Makefile + src/Makefile + tests/Makefile + examples/Makefile +]) AC_OUTPUT diff --git a/examples/Makefile.am b/examples/Makefile.am index 5376648..625e3cd 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -6,8 +6,7 @@ # this notice are preserved. This file is offered as-is, without any warranty. # -AM_CPPFLAGS = -I$(top_srcdir)/include - -noinst_PROGRAMS = sixdraw -sixdraw_SOURCES = sixdraw.c -sixdraw_LDADD = $(top_builddir)/src/libctlseqs.la +noinst_PROGRAMS = sixdraw +sixdraw_CPPFLAGS = -I$(top_srcdir)/include +sixdraw_SOURCES = sixdraw.c +sixdraw_LDADD = $(top_builddir)/src/libctlseqs.la diff --git a/examples/sixdraw.c b/examples/sixdraw.c index 6599327..dd4fbe3 100644 --- a/examples/sixdraw.c +++ b/examples/sixdraw.c @@ -1,5 +1,5 @@ /** - * sixdraw.c - draw lines on your terminal + * sixdraw.c - draw on your terminal * * Requires sixel graphics and 1016 mouse mode to run on your terminal. * These features are not widely supported. To save yourself from trouble, @@ -48,9 +48,8 @@ # define DEFAULT_TIMEOUT_MILLIS 500 #endif // !DEFAULT_TIMEOUT_MILLIS -#define DECRQM_UNREC 0 -#define DECRQM_SET 1 -#define DECRQM_RST 2 +#define DECRQM_SET 1 +#define DECRQM_RST 2 #define DECTCEM 25 #define DECSDM 80 @@ -126,7 +125,11 @@ terminate(struct sixdraw_ctx *ctx) // Restore original sixel mode. if (ctx->sixel_scroll) { - fprintf(ctx->out_file, ctx->legacy_xterm ? CTLSEQS_DECRST("%d") : CTLSEQS_DECSET("%d"), DECSDM); + fprintf( + ctx->out_file, + ctx->legacy_xterm ? CTLSEQS_DECRST("%d") : CTLSEQS_DECSET("%d"), + DECSDM + ); } // Restore original terminal modes. @@ -168,7 +171,9 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode, char const *name) print_error(ctx, "failed to get %s status", name); return false; } - if (result[0].num != mode || result[1].num == DECRQM_UNREC) { + if ( result[0].num != mode + || (result[1].num != DECRQM_SET && result[1].num != DECRQM_RST) + ) { print_error(ctx, "%s status not recognizable", name); return false; } @@ -250,7 +255,8 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv) break; case '?': default: - fprintf(ctx->out_file, "%s\n", "Usage: sixdraw [-t timeout] [-c line-color]"); + fprintf(ctx->out_file, "%s\n", + "Usage: sixdraw [-t timeout] [-c line-color]"); return false; } } @@ -264,7 +270,8 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv) char const *patterns[] = { CTLSEQS_RESP_PRIMARY_DA(CTLSEQS_PH_NUMS), CTLSEQS_RESP_DECRQM(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), - CTLSEQS_RESP_SGR_MOUSE(CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, "M"), + CTLSEQS_RESP_SGR_MOUSE( + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, "M"), CTLSEQS_RESP_XTVERSION(CTLSEQS_PH_STR), }; struct ctlseqs_matcher_options matcher_options = { @@ -339,7 +346,7 @@ prepare(struct sixdraw_ctx *ctx) return false; } - // Check terminal support for sixel graphics and DEC locator. + // Check terminal support for sixel graphics. fprintf(ctx->out_file, CTLSEQS_PRIMARY_DA()); ssize_t retval; do { @@ -384,9 +391,14 @@ prepare(struct sixdraw_ctx *ctx) } // Before patch #369, XTerm implemented DECSDM incorrectly. // See https://invisible-island.net/xterm/xterm.log.html#xterm_369 - ctx->sixel_scroll = result[1].num == (ctx->legacy_xterm ? DECRQM_RST : DECRQM_SET); + ctx->sixel_scroll + = result[1].num == (ctx->legacy_xterm ? DECRQM_RST : DECRQM_SET); if (ctx->sixel_scroll) { - fprintf(ctx->out_file, ctx->legacy_xterm ? CTLSEQS_DECSET("%d") : CTLSEQS_DECRST("%d"), DECSDM); + fprintf( + ctx->out_file, + ctx->legacy_xterm ? CTLSEQS_DECSET("%d") : CTLSEQS_DECRST("%d"), + DECSDM + ); } // Enable button event tracking mode. @@ -418,9 +430,14 @@ prepare(struct sixdraw_ctx *ctx) // Build the immutable part of sixel sequence. ctx->sixel_init_size = sizeof(SIXEL_SEQ_HEAD) - 1; - ctx->sixel_init_size += sprintf(sixel_seq + ctx->sixel_init_size, "%u;%u#0;2;%d;%d;%d#0", - ctx->ch_width, ctx->ch_height, ((ctx->line_color >> 16) & 0xFF) * 100 / 0xFF, - ((ctx->line_color >> 8) & 0xFF) * 100 / 0xFF, ((ctx->line_color >> 0) & 0xFF) * 100 / 0xFF); + ctx->sixel_init_size += sprintf( + sixel_seq + ctx->sixel_init_size, + "%u;%u#0;2;%d;%d;%d#0", + ctx->ch_width, ctx->ch_height, + ((ctx->line_color >> 16) & 0xFF) * 100 / 0xFF, + ((ctx->line_color >> 8) & 0xFF) * 100 / 0xFF, + ((ctx->line_color >> 0) & 0xFF) * 100 / 0xFF + ); return true; } @@ -428,27 +445,34 @@ prepare(struct sixdraw_ctx *ctx) static bool draw(struct sixdraw_ctx *ctx) { - 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); - fprintf(ctx->out_file, CTLSEQS_CUP("%d", "1") "Usage: Draw with mouse. Press Ctrl+C to exit.", ctx->rows); + 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 + ); + 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) { switch (ctlseqs_read(ctx->reader, ctx->matcher, -1)) { - case 2: // CTLSEQS_RESP_SGR_MOUSE - // Pixel coordinates start at 1 instead of 0. - print_sixel_dot(ctx, result[1].num - 1, result[2].num - 1); - break; - case CTLSEQS_NOSEQ: - // Press Ctrl+C to exit. - if (result[1].str[0] == 0x03) { - return true; - } - break; - case CTLSEQS_ERROR: - case CTLSEQS_NOMEM: - case CTLSEQS_EOF: - return false; + case 2: // CTLSEQS_RESP_SGR_MOUSE + // Pixel coordinates start at 1 instead of 0. + print_sixel_dot(ctx, result[1].num - 1, result[2].num - 1); + break; + case CTLSEQS_NOSEQ: + // Press Ctrl+C to exit. + if (result[1].str[0] == 0x03) { + return true; + } + break; + case CTLSEQS_ERROR: + case CTLSEQS_NOMEM: + case CTLSEQS_EOF: + return false; } } } diff --git a/include/ctlseqs.h b/include/ctlseqs.h index 9c7660c..9762664 100644 --- a/include/ctlseqs.h +++ b/include/ctlseqs.h @@ -1,8 +1,8 @@ /** * ctlseqs.h - helper library for control sequences - * + * * Copyright (C) 2020,2021 CismonX - * + * * This file is part of the ctlseqs library. * * ctlseqs is free software: you can redistribute it and/or modify @@ -30,89 +30,166 @@ /* C0 Control Functions */ -#define CTLSEQS_NUL "\x00" // Null -#define CTLSEQS_SOH "\x01" // Start of Heading -#define CTLSEQS_STX "\x02" // Start of Text -#define CTLSEQS_ETX "\x03" // End of Text -#define CTLSEQS_EOT "\x04" // End of Transmission -#define CTLSEQS_ENQ "\x05" // Enquiry -#define CTLSEQS_ACK "\x06" // Acknowledge -#define CTLSEQS_BEL "\x07" // Bell -#define CTLSEQS_BS "\x08" // Backspace -#define CTLSEQS_HT "\x09" // Horizontal Tab -#define CTLSEQS_LF "\x0a" // Line Feed -#define CTLSEQS_VT "\x0b" // Vertical Tab -#define CTLSEQS_FF "\x0c" // Form Feed or New Page -#define CTLSEQS_CR "\x0d" // Carriage Return -#define CTLSEQS_SO "\x0e" // Shift Out -#define CTLSEQS_SI "\x0f" // Shift In -#define CTLSEQS_DLE "\x10" // Data Link Escape -#define CTLSEQS_DC1 "\x11" // Device Control 1 -#define CTLSEQS_DC2 "\x12" // Device Control 2 -#define CTLSEQS_DC3 "\x13" // Device Control 3 -#define CTLSEQS_DC4 "\x14" // Device Control 4 -#define CTLSEQS_NAK "\x15" // Negative Acknowledgement -#define CTLSEQS_SYN "\x16" // Synchronous Idle -#define CTLSEQS_ETB "\x17" // End of Transmission Block -#define CTLSEQS_CAN "\x18" // Cancel -#define CTLSEQS_EM "\x19" // End of Medium -#define CTLSEQS_SUB "\x1a" // Substitute -#define CTLSEQS_ESC "\x1b" // Escape -#define CTLSEQS_FS "\x1c" // File Separator -#define CTLSEQS_GS "\x1d" // Group Separator -#define CTLSEQS_RS "\x1e" // Record Separator -#define CTLSEQS_US "\x1f" // Unit Separator -#define CTLSEQS_SP "\x20" // Space -#define CTLSEQS_DEL "\x7f" // Delete +// Null +#define CTLSEQS_NUL "\x00" +// Start of Heading +#define CTLSEQS_SOH "\x01" +// Start of Text +#define CTLSEQS_STX "\x02" +// End of Text +#define CTLSEQS_ETX "\x03" +// End of Transmission +#define CTLSEQS_EOT "\x04" +// Enquiry +#define CTLSEQS_ENQ "\x05" +// Acknowledge +#define CTLSEQS_ACK "\x06" +// Bell +#define CTLSEQS_BEL "\x07" +// Backspace +#define CTLSEQS_BS "\x08" +// Horizontal Tab +#define CTLSEQS_HT "\x09" +// Line Feed +#define CTLSEQS_LF "\x0a" +// Vertical Tab +#define CTLSEQS_VT "\x0b" +// Form Feed or New Page +#define CTLSEQS_FF "\x0c" +// Carriage Return +#define CTLSEQS_CR "\x0d" +// Shift Out +#define CTLSEQS_SO "\x0e" +// Shift In +#define CTLSEQS_SI "\x0f" +// Data Link Escape +#define CTLSEQS_DLE "\x10" +// Device Control 1 +#define CTLSEQS_DC1 "\x11" +// Device Control 2 +#define CTLSEQS_DC2 "\x12" +// Device Control 3 +#define CTLSEQS_DC3 "\x13" +// Device Control 4 +#define CTLSEQS_DC4 "\x14" +// Negative Acknowledgement +#define CTLSEQS_NAK "\x15" +// Synchronous Idle +#define CTLSEQS_SYN "\x16" +// End of Transmission Block +#define CTLSEQS_ETB "\x17" +// Cancel +#define CTLSEQS_CAN "\x18" +// End of Medium +#define CTLSEQS_EM "\x19" +// Substitute +#define CTLSEQS_SUB "\x1a" +// Escape +#define CTLSEQS_ESC "\x1b" +// File Separator +#define CTLSEQS_FS "\x1c" +// Group Separator +#define CTLSEQS_GS "\x1d" +// Record Separator +#define CTLSEQS_RS "\x1e" +// Unit Separator +#define CTLSEQS_US "\x1f" +// Space +#define CTLSEQS_SP "\x20" +// Delete +#define CTLSEQS_DEL "\x7f" /* C1 Control Functions (2-character 7-bit representation) */ -#define CTLSEQS_BPH CTLSEQS_ESC "B" // Break Permitted Here -#define CTLSEQS_NBH CTLSEQS_ESC "C" // No Break Here -#define CTLSEQS_IND CTLSEQS_ESC "D" // Index -#define CTLSEQS_NEL CTLSEQS_ESC "E" // Next Line -#define CTLSEQS_SSA CTLSEQS_ESC "F" // Start of Selected Area -#define CTLSEQS_ESA CTLSEQS_ESC "G" // End of Selected Area -#define CTLSEQS_HTS CTLSEQS_ESC "H" // Character Tabulation Set -#define CTLSEQS_VTS CTLSEQS_ESC "J" // Line Tabulation Set -#define CTLSEQS_PLD CTLSEQS_ESC "K" // Partial Line Forward -#define CTLSEQS_PLU CTLSEQS_ESC "L" // Partial Line Backward -#define CTLSEQS_RI CTLSEQS_ESC "M" // Reverse Index -#define CTLSEQS_SS2 CTLSEQS_ESC "N" // Single Shift 2 -#define CTLSEQS_SS3 CTLSEQS_ESC "O" // Single Shift 3 -#define CTLSEQS_DCS CTLSEQS_ESC "P" // Device Control String -#define CYLSEQS_PU1 CTLSEQS_ESC "Q" // Private Use 1 -#define CYLSEQS_PU2 CTLSEQS_ESC "R" // Private Use 2 -#define CYLSEQS_STS CTLSEQS_ESC "S" // Set Transmit State -#define CTLSEQS_CCH CTLSEQS_ESC "T" // Cancel Character -#define CTLSEQS_MW CTLSEQS_ESC "U" // Message Waiting -#define CTLSEQS_SPA CTLSEQS_ESC "V" // Start of Guarded Area -#define CTLSEQS_EPA CTLSEQS_ESC "W" // End of Guarded Area -#define CTLSEQS_SOS CTLSEQS_ESC "X" // Start of String -#define CTLSEQS_HTJ CTLSEQS_ESC "Y" // Character Tabulation with Justification -#define CYLSEQS_SCI CTLSEQS_ESC "Z" // Single Character Introducer -#define CTLSEQS_CSI CTLSEQS_ESC "[" // Control Sequence Introducer -#define CTLSEQS_ST CTLSEQS_ESC "\\" // String Terminator -#define CTLSEQS_OSC CTLSEQS_ESC "]" // Operating System Command -#define CTLSEQS_PM CTLSEQS_ESC "^" // Privacy Message -#define CTLSEQS_APC CTLSEQS_ESC "_" // Application Program Command +// Break Permitted Here +#define CTLSEQS_BPH CTLSEQS_ESC "B" +// No Break Here +#define CTLSEQS_NBH CTLSEQS_ESC "C" +// Index +#define CTLSEQS_IND CTLSEQS_ESC "D" +// Next Line +#define CTLSEQS_NEL CTLSEQS_ESC "E" +// Start of Selected Area +#define CTLSEQS_SSA CTLSEQS_ESC "F" +// End of Selected Area +#define CTLSEQS_ESA CTLSEQS_ESC "G" +// Character Tabulation Set +#define CTLSEQS_HTS CTLSEQS_ESC "H" +// Line Tabulation Set +#define CTLSEQS_VTS CTLSEQS_ESC "J" +// Partial Line Forward +#define CTLSEQS_PLD CTLSEQS_ESC "K" +// Partial Line Backward +#define CTLSEQS_PLU CTLSEQS_ESC "L" +// Reverse Index +#define CTLSEQS_RI CTLSEQS_ESC "M" +// Single Shift 2 +#define CTLSEQS_SS2 CTLSEQS_ESC "N" +// Single Shift 3 +#define CTLSEQS_SS3 CTLSEQS_ESC "O" +// Device Control String +#define CTLSEQS_DCS CTLSEQS_ESC "P" +// Private Use 1 +#define CTLSEQS_PU1 CTLSEQS_ESC "Q" +// Private Use 2 +#define CTLSEQS_PU2 CTLSEQS_ESC "R" +// Set Transmit State +#define CTLSEQS_STS CTLSEQS_ESC "S" +// Cancel Character +#define CTLSEQS_CCH CTLSEQS_ESC "T" +// Message Waiting +#define CTLSEQS_MW CTLSEQS_ESC "U" +// Start of Guarded Area +#define CTLSEQS_SPA CTLSEQS_ESC "V" +// End of Guarded Area +#define CTLSEQS_EPA CTLSEQS_ESC "W" +// Start of String +#define CTLSEQS_SOS CTLSEQS_ESC "X" +// Character Tabulation with Justification +#define CTLSEQS_HTJ CTLSEQS_ESC "Y" +// Single Character Introducer +#define CTLSEQS_SCI CTLSEQS_ESC "Z" +// Control Sequence Introducer +#define CTLSEQS_CSI CTLSEQS_ESC "[" +// String Terminator +#define CTLSEQS_ST CTLSEQS_ESC "\\" +// Operating System Command +#define CTLSEQS_OSC CTLSEQS_ESC "]" +// Privacy Message +#define CTLSEQS_PM CTLSEQS_ESC "^" +// Application Program Command +#define CTLSEQS_APC CTLSEQS_ESC "_" /* Controls beginning with ESC */ -#define CTLSEQS_S7C1T() CTLSEQS_ESC " F" // 7-bit controls -#define CTLSEQS_S8C1T() CTLSEQS_ESC " G" // 8-bit controls -#define CTLSEQS_DECDHL_TOP() CTLSEQS_ESC "#3" // DEC double-height line, top half -#define CTLSEQS_DECDHL_BOTOM() CTLSEQS_ESC "#4" // DEC double-height line, bottom half -#define CTLSEQS_DECSWL() CTLSEQS_ESC "#5" // DEC single-width line -#define CTLSEQS_DECDWL() CTLSEQS_ESC "#6" // DEC double-width line -#define CTLSEQS_DECALN() CTLSEQS_ESC "#8" // DEC Screen Alignment Test -#define CTLSEQS_DECBI() CTLSEQS_ESC "6" // Back Index -#define CTLSEQS_DECSC() CTLSEQS_ESC "7" // Save Cursor -#define CTLSEQS_DECRC() CTLSEQS_ESC "8" // Restore Cursor -#define CTLSEQS_DECFI() CTLSEQS_ESC "9" // Forward Index -#define CTLSEQS_DECKPAM() CTLSEQS_ESC "=" // Application Keypad -#define CTLSEQS_DECKPNM() CTLSEQS_ESC ">" // Normal Keypad -#define CTLSEQS_RIS() CTLSEQS_ESC "c" // Full Reset +// 7-bit controls +#define CTLSEQS_S7C1T() CTLSEQS_ESC " F" +// 8-bit controls +#define CTLSEQS_S8C1T() CTLSEQS_ESC " G" +// DEC double-height line, top half +#define CTLSEQS_DECDHL_TOP() CTLSEQS_ESC "#3" +// DEC double-height line, bottom half +#define CTLSEQS_DECDHL_BOTOM() CTLSEQS_ESC "#4" +// DEC single-width line +#define CTLSEQS_DECSWL() CTLSEQS_ESC "#5" +// DEC double-width line +#define CTLSEQS_DECDWL() CTLSEQS_ESC "#6" +// DEC Screen Alignment Test +#define CTLSEQS_DECALN() CTLSEQS_ESC "#8" +// Back Index +#define CTLSEQS_DECBI() CTLSEQS_ESC "6" +// Save Cursor +#define CTLSEQS_DECSC() CTLSEQS_ESC "7" +// Restore Cursor +#define CTLSEQS_DECRC() CTLSEQS_ESC "8" +// Forward Index +#define CTLSEQS_DECFI() CTLSEQS_ESC "9" +// Application Keypad +#define CTLSEQS_DECKPAM() CTLSEQS_ESC "=" +// Normal Keypad +#define CTLSEQS_DECKPNM() CTLSEQS_ESC ">" +// Full Reset +#define CTLSEQS_RIS() CTLSEQS_ESC "c" /* Device-Control functions */ @@ -172,11 +249,13 @@ // Scroll up $n Lines #define CTLSEQS_SU(n) CTLSEQS_CSI n "S" // Set or request graphics attribute -#define CTLSEQS_XTSMGRAPHICS(i1, i2, is) CTLSEQS_CSI "?" i1 ";" i2 ";" is "S" +#define CTLSEQS_XTSMGRAPHICS(i1, i2, is) \ + CTLSEQS_CSI "?" i1 ";" i2 ";" is "S" // Scroll Down $n Line(s) #define CTLSEQS_SD(n) CTLSEQS_CSI n "T" // Initiate highlight mouse tracking -#define CTLSEQS_XTHIMOUSE(f, x, y, fr, lr) CTLSEQS_CSI f ";" x ";" y ";" fr ";" lr "T" +#define CTLSEQS_XTHIMOUSE(f, x, y, fr, lr) \ + CTLSEQS_CSI f ";" x ";" y ";" fr ";" lr "T" // Reset title mode features to default value #define CTLSEQS_XTRMTITLE(is) CTLSEQS_CSI ">" is "T" // Erase $n Character(s) @@ -211,7 +290,7 @@ #define CTLSEQS_MC(i) CTLSEQS_CSI i "i" // Media Copy, DEC-specific #define CTLSEQS_MC_DEC(i) CTLSEQS_CSI "?" i "i" -// Reset Mode +// Reset Mode #define CTLSEQS_RM(i) CTLSEQS_CSI i "l" // DEC Private Mode Reset #define CTLSEQS_DECRST(i) CTLSEQS_CSI "?" i "l" @@ -248,7 +327,8 @@ // Restore DEC Private Mode Values #define CTLSEQS_XTRESTORE(is) CTLSEQS_CSI "?" is "r" // Change Attributes in Rectangular Area -#define CTLSEQS_DECCARA(t, l, b, r, i) CTLSEQS_CSI t ";" l ";" b ";" r ";" i "$r" +#define CTLSEQS_DECCARA(t, l, b, r, i) \ + CTLSEQS_CSI t ";" l ";" b ";" r ";" i "$r" // Save cursor #define CTLSEQS_SCOSC() CTLSEQS_CSI "s" // Set left and right margins @@ -262,39 +342,47 @@ // Set warning-bell volume #define CTLSEQS_DECSWBV(i) CTLSEQS_CSI i " t" // Reverse Attributes in Rectangular Area -#define CTLSEQS_DECRARA(t, l, b, r, i) CTLSEQS_CSI t ";" l ";" b ";" r ";" i "$t" +#define CTLSEQS_DECRARA(t, l, b, r, i) \ + CTLSEQS_CSI t ";" l ";" b ";" r ";" i "$t" // Restore cursor #define CTLSEQS_SCORC() CTLSEQS_CSI "u" // Set margin-bell volume #define CTLSEQS_DECSMBV(i) CTLSEQS_CSI i " u" // Copy Rectangular Area -#define CTLSEQS_DECCRA(t, l, b, r, sp, dt, dl, dp) CTLSEQS_CSI t ";" l ";" b ";" r ";" sp ";" dt ";" dl ";" dp "$v" +#define CTLSEQS_DECCRA(t, l, b, r, sp, dt, dl, dp) \ + CTLSEQS_CSI t ";" l ";" b ";" r ";" sp ";" dt ";" dl ";" dp "$v" // Request presentation state report #define CTLSEQS_DECRQPSR(i) CTLSEQS_CSI i "$w" // Enable Filter Rectangle -#define CTLSEQS_DECEFR(t, l, b, r) CTLSEQS_CSI t ";" l ";" b ";" r "'w" +#define CTLSEQS_DECEFR(t, l, b, r) \ + CTLSEQS_CSI t ";" l ";" b ";" r "'w" // Request Terminal Parameters #define CTLSEQS_DECREQTPARM(i) CTLSEQS_CSI i "x" // Select Attribute Change Extent #define CTLSEQS_DECSACE(i) CTLSEQS_CSI i "*x" // Fill Rectangular Area -#define CTLSEQS_DECFRA(c, t, l, b, r) CTLSEQS_CSI c ";" t ";" l ";" b ";" r "$x" +#define CTLSEQS_DECFRA(c, t, l, b, r) \ + CTLSEQS_CSI c ";" t ";" l ";" b ";" r "$x" // Select checksum extension #define CTLSEQS_XTCHECKSUM(i) CTLSEQS_CSI i "#y" // Request Checksum of Rectangular Area -#define CTLSEQS_DECRQCRA(id, p, t, l, b, r) CTLSEQS_CSI id ";" p ";" t ";" l ";" b ";" r "*y" +#define CTLSEQS_DECRQCRA(id, p, t, l, b, r) \ + CTLSEQS_CSI id ";" p ";" t ";" l ";" b ";" r "*y" // Enable Locator Reporting #define CTLSEQS_DECELR(i1, i2) CTLSEQS_CSI i1 ";" i2 "'z" // Erase Rectangular Area -#define CTLSEQS_DECERA(t, l, b, r) CTLSEQS_CSI t ";" l ";" b ";" r "$z" +#define CTLSEQS_DECERA(t, l, b, r) \ + CTLSEQS_CSI t ";" l ";" b ";" r "$z" // Select Locator Events #define CTLSEQS_DECSLE(is) CTLSEQS_CSI is "'{" // Push video attributes onto stack #define CTLSEQS_XTPUSHSGR(is) CTLSEQS_CSI is "#{" // Selective Erase Rectangular Area -#define CTLSEQS_DECSERA(t, l, b, r) CTLSEQS_CSI t ";" l ";" b ";" r "${" +#define CTLSEQS_DECSERA(t, l, b, r) \ + CTLSEQS_CSI t ";" l ";" b ";" r "${" // Report selected graphic rendition -#define CTLSEQS_XTREPORTSGR(t, l, b, r) CTLSEQS_CSI t ";" l ";" b ";" r "$|" +#define CTLSEQS_XTREPORTSGR(t, l, b, r) \ + CTLSEQS_CSI t ";" l ";" b ";" r "$|" // Select columns per page #define CTLSEQS_DECSCPP(i) CTLSEQS_CSI i "$|" // Request Locator Position @@ -324,7 +412,8 @@ // Primary DA response message #define CTLSEQS_RESP_PRIMARY_DA(ns) CTLSEQS_CSI "?" ns "c" // Secondary DA response message -#define CTLSEQS_RESP_SECONDARY_DA(n1, n2, n3) CTLSEQS_CSI ">" n1 ";" n2 ";" n3 "c" +#define CTLSEQS_RESP_SECONDARY_DA(n1, n2, n3) \ + CTLSEQS_CSI ">" n1 ";" n2 ";" n3 "c" // DECLRP response message #define CTLSEQS_RESP_DECXCPR(n1, n2) CTLSEQS_CSI "?" n1 ";" n2 "R" // DSR response message @@ -342,34 +431,58 @@ // DECRQCRA response message #define CTLSEQS_RESP_DECRQCRA(n, s) CTLSEQS_DCS n "!~" s CTLSEQS_ST // DECRQLP response message -#define CTLSEQS_RESP_DECRQLP(e, b, row, col, p) CTLSEQS_CSI e ";" b ";" row ";" col ";" p "&w" +#define CTLSEQS_RESP_DECRQLP(e, b, row, col, p) \ + CTLSEQS_CSI e ";" b ";" row ";" col ";" p "&w" // Mouse response in SGR mouse mode -#define CTLSEQS_RESP_SGR_MOUSE(n, col, row, c) CTLSEQS_CSI "<" n ";" col ";" row c +#define CTLSEQS_RESP_SGR_MOUSE(n, col, row, c) \ + CTLSEQS_CSI "<" n ";" col ";" row c /// PC-Style Function Keys -#define CTLSEQS_KEY_UP() CTLSEQS_CSI "A" // Up arrow key -#define CTLSEQS_KEY_DOWN() CTLSEQS_CSI "B" // Down arrow key -#define CTLSEQS_KEY_RIGHT() CTLSEQS_CSI "C" // Right arrow key -#define CTLSEQS_KEY_LEFT() CTLSEQS_CSI "D" // Left arrow key -#define CTLSEQS_KEY_HOME() CTLSEQS_CSI "H" // Home key -#define CTLSEQS_KEY_END() CTLSEQS_CSI "F" // End key -#define CTLSEQS_KEY_INSERT() CTLSEQS_CSI "2~" // Insert key -#define CTLSEQS_KEY_DELETE() CTLSEQS_CSI "3~" // Delete key -#define CTLSEQS_KEY_PGUP() CTLSEQS_CSI "5~" // Page Up key -#define CTLSEQS_KEY_PGDN() CTLSEQS_CSI "6~" // Page Down key -#define CTLSEQS_KEY_F1() CTLSEQS_SS3 "P" // F1 key -#define CTLSEQS_KEY_F2() CTLSEQS_SS3 "Q" // F2 key -#define CTLSEQS_KEY_F3() CTLSEQS_SS3 "R" // F3 key -#define CTLSEQS_KEY_F4() CTLSEQS_SS3 "S" // F4 key -#define CTLSEQS_KEY_F5() CTLSEQS_CSI "15~" // F5 key -#define CTLSEQS_KEY_F6() CTLSEQS_CSI "17~" // F6 key -#define CTLSEQS_KEY_F7() CTLSEQS_CSI "18~" // F7 key -#define CTLSEQS_KEY_F8() CTLSEQS_CSI "19~" // F8 key -#define CTLSEQS_KEY_F9() CTLSEQS_CSI "20~" // F9 key -#define CTLSEQS_KEY_F10() CTLSEQS_CSI "21~" // F10 key -#define CTLSEQS_KEY_F11() CTLSEQS_CSI "23~" // F11 key -#define CTLSEQS_KEY_F12() CTLSEQS_CSI "24~" // F12 key +// Up arrow key +#define CTLSEQS_KEY_UP() CTLSEQS_CSI "A" +// Down arrow key +#define CTLSEQS_KEY_DOWN() CTLSEQS_CSI "B" +// Right arrow key +#define CTLSEQS_KEY_RIGHT() CTLSEQS_CSI "C" +// Left arrow key +#define CTLSEQS_KEY_LEFT() CTLSEQS_CSI "D" +// Home key +#define CTLSEQS_KEY_HOME() CTLSEQS_CSI "H" +// End key +#define CTLSEQS_KEY_END() CTLSEQS_CSI "F" +// Insert key +#define CTLSEQS_KEY_INSERT() CTLSEQS_CSI "2~" +// Delete key +#define CTLSEQS_KEY_DELETE() CTLSEQS_CSI "3~" +// Page Up key +#define CTLSEQS_KEY_PGUP() CTLSEQS_CSI "5~" +// Page Down key +#define CTLSEQS_KEY_PGDN() CTLSEQS_CSI "6~" +// F1 key +#define CTLSEQS_KEY_F1() CTLSEQS_SS3 "P" +// F2 key +#define CTLSEQS_KEY_F2() CTLSEQS_SS3 "Q" +// F3 key +#define CTLSEQS_KEY_F3() CTLSEQS_SS3 "R" +// F4 key +#define CTLSEQS_KEY_F4() CTLSEQS_SS3 "S" +// F5 key +#define CTLSEQS_KEY_F5() CTLSEQS_CSI "15~" +// F6 key +#define CTLSEQS_KEY_F6() CTLSEQS_CSI "17~" +// F7 key +#define CTLSEQS_KEY_F7() CTLSEQS_CSI "18~" +// F8 key +#define CTLSEQS_KEY_F8() CTLSEQS_CSI "19~" +// F9 key +#define CTLSEQS_KEY_F9() CTLSEQS_CSI "20~" +// F10 key +#define CTLSEQS_KEY_F10() CTLSEQS_CSI "21~" +// F11 key +#define CTLSEQS_KEY_F11() CTLSEQS_CSI "23~" +// F12 key +#define CTLSEQS_KEY_F12() CTLSEQS_CSI "24~" #ifdef __cplusplus # include @@ -381,19 +494,29 @@ /* Placeholders */ -#define CTLSEQS_PH_NUM "\x0e" // CSI Parameter Bytes, numbers only -#define CTLSEQS_PH_NUMS "\x0f" // CSI Parameter Bytes, multiple numbers separated by semicolon -#define CTLSEQS_PH_STR "\x10" // String, printable characters only -#define CTLSEQS_PH_CMDSTR "\x11" // Command String -#define CTLSEQS_PH_CSI_PARAM "\x12" // CSI Parameter Bytes -#define CTLSEQS_PH_CSI_INTMD "\x13" // CSI Intermediate Bytes -#define CTLSEQS_PH_HEXNUM "\x14" // Printable characters representing a hexadecimal number -#define CTLSEQS_PH_CHRSTR "\x15" // Character String +// CSI Parameter Bytes, numbers only +#define CTLSEQS_PH_NUM "\x0e" +// CSI Parameter Bytes, multiple numbers separated by semicolon +#define CTLSEQS_PH_NUMS "\x0f" +// String, printable characters only +#define CTLSEQS_PH_STR "\x10" +// Command String +#define CTLSEQS_PH_CMDSTR "\x11" +// CSI Parameter Bytes +#define CTLSEQS_PH_CSI_PARAM "\x12" +// CSI Intermediate Bytes +#define CTLSEQS_PH_CSI_INTMD "\x13" +// Printable characters representing a hexadecimal number +#define CTLSEQS_PH_HEXNUM "\x14" +// Character String +#define CTLSEQS_PH_CHRSTR "\x15" /* Reader option flags */ -#define CTLSEQS_READER_NO_POLL (1 << 0) // Do not poll() before read() -#define CTLSEQS_READER_SAVE_MATCHED_SEQS (1 << 1) // Save successfully matched sequence to buffer +// Do not poll() before read() +#define CTLSEQS_READER_NO_POLL (1 << 0) +// Save successfully matched sequence to buffer +#define CTLSEQS_READER_SAVE_MATCHED_SEQS (1 << 1) /* Function return status codes */ @@ -439,28 +562,50 @@ struct ctlseqs_matcher * ctlseqs_matcher_init(); int -ctlseqs_matcher_config(struct ctlseqs_matcher *matcher, struct ctlseqs_matcher_options const *options); +ctlseqs_matcher_config( + struct ctlseqs_matcher *matcher, + struct ctlseqs_matcher_options const *options +); void -ctlseqs_matcher_free(struct ctlseqs_matcher *matcher); +ctlseqs_matcher_free( + struct ctlseqs_matcher *matcher +); ssize_t -ctlseqs_match(struct ctlseqs_matcher const *matcher, char const *str, size_t str_len, union ctlseqs_value *result); +ctlseqs_match( + struct ctlseqs_matcher const *matcher, + char const *str, + size_t str_len, + union ctlseqs_value *result +); struct ctlseqs_reader * ctlseqs_reader_init(); int -ctlseqs_reader_config(struct ctlseqs_reader *reader, struct ctlseqs_reader_options const *options); +ctlseqs_reader_config( + struct ctlseqs_reader *reader, + struct ctlseqs_reader_options const *options +); ssize_t -ctlseqs_read(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher, int timeout); +ctlseqs_read( + struct ctlseqs_reader *reader, + struct ctlseqs_matcher const *matcher, + int timeout +); void -ctlseqs_purge(struct ctlseqs_reader *reader, size_t nbytes); +ctlseqs_purge( + struct ctlseqs_reader *reader, + size_t nbytes +); void -ctlseqs_reader_free(struct ctlseqs_reader *reader); +ctlseqs_reader_free( + struct ctlseqs_reader *reader +); #ifdef __cplusplus } diff --git a/src/Makefile.am b/src/Makefile.am index ad53c1d..76ce2a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,8 +6,7 @@ # this notice are preserved. This file is offered as-is, without any warranty. # -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_LDFLAGS = -version-info $(CTLSEQS_LT_VERSION) - -lib_LTLIBRARIES = libctlseqs.la -libctlseqs_la_SOURCES = ctlseqs.c +lib_LTLIBRARIES = libctlseqs.la +libctlseqs_la_CPPFLAGS = -I$(top_srcdir)/include +libctlseqs_la_SOURCES = ctlseqs.c +libctlseqs_la_LDFLAGS = -version-info $(CTLSEQS_LT_VERSION) diff --git a/src/ctlseqs.c b/src/ctlseqs.c index 621fa51..d7e8455 100644 --- a/src/ctlseqs.c +++ b/src/ctlseqs.c @@ -159,142 +159,196 @@ struct ctlseqs_reader { }; ctlseqs_hot static inline int -ctlseqs_poll(struct pollfd *pollfd, int timeout) -{ +ctlseqs_poll( + struct pollfd *pollfd, + int timeout +) { int nevents = poll(pollfd, 1, timeout); - if (nevents == -1) { - return errno == EINTR ? CTLSEQS_INTR : CTLSEQS_ERROR; - } - if (nevents == 0) { + switch (nevents) { + case 0: return CTLSEQS_TIMEOUT; + case 1: + if (ctlseqs_likely(pollfd->revents & POLLIN)) { + return CTLSEQS_OK; + } else if (pollfd->revents & POLLHUP) { + return CTLSEQS_EOF; + } else { + return CTLSEQS_ERROR; + } + default: + if (errno == EINTR) { + return CTLSEQS_INTR; + } else { + return CTLSEQS_ERROR; + } } - if (ctlseqs_likely(pollfd->revents & POLLIN)) { - return CTLSEQS_OK; - } - return pollfd->revents & POLLHUP ? CTLSEQS_EOF : CTLSEQS_ERROR; } ctlseqs_hot static inline int -ctlseqs_do_read(struct ctlseqs_reader *reader) -{ +ctlseqs_do_read( + struct ctlseqs_reader *reader +) { size_t offset = reader->buf_start + reader->last_idx; - ssize_t nbytes = read(reader->pollfd.fd, reader->rbuf + offset, reader->readlen - offset); - if (ctlseqs_unlikely(nbytes == -1)) { + ssize_t nbytes = read( + reader->pollfd.fd, + reader->rbuf + offset, + reader->readlen - offset + ); + switch (nbytes) { + case -1: if (errno == EAGAIN || errno == EWOULDBLOCK) { return CTLSEQS_TIMEOUT; + } else if (errno == EINTR) { + return CTLSEQS_INTR; + } else { + return CTLSEQS_ERROR; } - return errno == EINTR ? CTLSEQS_INTR : CTLSEQS_ERROR; - } - if (ctlseqs_unlikely(nbytes == 0)) { + case 0: return CTLSEQS_EOF; + default: + reader->buf_end += nbytes; + return CTLSEQS_OK; } - reader->buf_end += nbytes; - return CTLSEQS_OK; } ctlseqs_hot static enum ctlseqs_state -ctlseqs_state_transition(enum ctlseqs_state state, char ch) -{ +ctlseqs_state_transition( + enum ctlseqs_state state, + char ch +) { switch (state) { - case ctlseqs_state_none: - return ch == 0x1b ? ctlseqs_state_esc : ctlseqs_state_err; - case ctlseqs_state_esc: - switch (ch) { - case '[': - return ctlseqs_state_csi; - case 'N': - case 'O': - return ctlseqs_state_ss; - case 'P': - case ']': - case '_': - case '^': - return ctlseqs_state_cmdstr; - case 'X': - return ctlseqs_state_ctlstr; - default: - return (ch >= ' ' && ch <= '~') ? ctlseqs_state_done : ctlseqs_state_err; - } - case ctlseqs_state_csi: - if (ch >= '0' && ch <= '?') { - return state; - } else if (ch >= ' ' && ch <= '/') { - return ctlseqs_state_csi_intmd; - } - return (ch >= '@' && ch <= '~') ? ctlseqs_state_done : ctlseqs_state_err; - case ctlseqs_state_csi_intmd: - if (ch >= ' ' && ch <= '/') { - return state; - } - return (ch >= '@' && ch <= '~') ? ctlseqs_state_done : ctlseqs_state_err; - case ctlseqs_state_cmdstr: - if (ch == 0x1b) { - return ctlseqs_state_str_end; - } else if (ch < 0x08 || ch > '~' || (ch > 0x0d && ch < ' ')) { + case ctlseqs_state_none: + if (ch == 0x1b) { + return ctlseqs_state_esc; + } else { + return ctlseqs_state_err; + } + case ctlseqs_state_esc: + switch (ch) { + case '[': + return ctlseqs_state_csi; + case 'N': + case 'O': + return ctlseqs_state_ss; + case 'P': + case ']': + case '_': + case '^': + return ctlseqs_state_cmdstr; + case 'X': + return ctlseqs_state_ctlstr; + default: + if (ch >= ' ' && ch <= '~') { + return ctlseqs_state_done; + } else { return ctlseqs_state_err; } + } + case ctlseqs_state_csi: + if (ch >= '0' && ch <= '?') { return state; - case ctlseqs_state_ss: - return (ch >= ' ' && ch <= '~') ? ctlseqs_state_done : ctlseqs_state_err; - case ctlseqs_state_ctlstr: - return ch == 0x1b ? ctlseqs_state_str_end : state; - case ctlseqs_state_str_end: - return ch == '\\' ? ctlseqs_state_done : ctlseqs_state_err; - default: - ctlseqs_unreachable(); + } else if (ch >= ' ' && ch <= '/') { + return ctlseqs_state_csi_intmd; + } else if (ch >= '@' && ch <= '~') { + return ctlseqs_state_done; + } else { + return ctlseqs_state_err; + } + case ctlseqs_state_csi_intmd: + if (ch >= ' ' && ch <= '/') { return state; + } else if (ch >= '@' && ch <= '~') { + return ctlseqs_state_done; + } else { + return ctlseqs_state_err; + } + case ctlseqs_state_cmdstr: + if (ch == 0x1b) { + return ctlseqs_state_str_end; + } else if (ch < 0x08 || ch > '~' || (ch > 0x0d && ch < ' ')) { + return ctlseqs_state_err; + } else { + return state; + } + case ctlseqs_state_ss: + if (ch >= ' ' && ch <= '~') { + return ctlseqs_state_done; + } else { + return ctlseqs_state_err; + } + case ctlseqs_state_ctlstr: + if (ch == 0x1b) { + return ctlseqs_state_str_end; + } else { + return state; + } + case ctlseqs_state_str_end: + if (ch == '\\') { + return ctlseqs_state_done; + } else { + return ctlseqs_state_err; + } + default: + ctlseqs_unreachable(); + return state; } } ctlseqs_hot static char const * -ctlseqs_fetch_value(char const *seq, int type, union ctlseqs_value **buf) -{ +ctlseqs_fetch_value( + char const *seq, + int type, + union ctlseqs_value **buf +) { size_t cnt; unsigned long num; char *endptr = NULL; union ctlseqs_value *buf_val = *buf; switch (type) { - case ctlseqs_ph_num: - CTLSEQS_VALUE_NUM(10); - case ctlseqs_ph_nums: - for (cnt = 1; ; ++cnt) { - errno = 0; - num = strtoul(seq, &endptr, 10); - if (errno || seq == endptr) { - return NULL; - } - buf_val[cnt].num = num; - if (endptr[0] != ';') { - break; - } - seq = endptr + 1; + case ctlseqs_ph_num: + CTLSEQS_VALUE_NUM(10); + case ctlseqs_ph_nums: + for (cnt = 1; ; ++cnt) { + errno = 0; + num = strtoul(seq, &endptr, 10); + if (errno || seq == endptr) { + return NULL; } - buf_val[0].len = cnt; - *buf += cnt + 1; - return endptr; - case ctlseqs_ph_str: - CTLSEQS_VALUE_STR(num < ' ' || num > '~'); - case ctlseqs_ph_cmdstr: - CTLSEQS_VALUE_STR(num < 0x08 || num > '~' || (num > 0x0d && num < ' ')); - case ctlseqs_ph_csi_param: - CTLSEQS_VALUE_STR(num < '0' || num > '?'); - case ctlseqs_ph_csi_intmd: - CTLSEQS_VALUE_STR(num < ' ' || num > '/'); - case ctlseqs_ph_hexnum: - CTLSEQS_VALUE_NUM(16); - case ctlseqs_ph_chrstr: - CTLSEQS_VALUE_STR(num > 0x7f); - default: - ctlseqs_unreachable(); - return NULL; + buf_val[cnt].num = num; + if (endptr[0] != ';') { + break; + } + seq = endptr + 1; + } + buf_val[0].len = cnt; + *buf += cnt + 1; + return endptr; + case ctlseqs_ph_str: + CTLSEQS_VALUE_STR(num < ' ' || num > '~'); + case ctlseqs_ph_cmdstr: + CTLSEQS_VALUE_STR(num < 0x08 || num > '~' || num > 0x0d && num < ' '); + case ctlseqs_ph_csi_param: + CTLSEQS_VALUE_STR(num < '0' || num > '?'); + case ctlseqs_ph_csi_intmd: + CTLSEQS_VALUE_STR(num < ' ' || num > '/'); + case ctlseqs_ph_hexnum: + CTLSEQS_VALUE_NUM(16); + case ctlseqs_ph_chrstr: + CTLSEQS_VALUE_STR(num > 0x7f); + default: + ctlseqs_unreachable(); + return NULL; } } ctlseqs_hot static ssize_t -ctlseqs_match_pattern(struct ctlseqs_matcher const *matcher, struct ctlseqs_match_args const *args) -{ +ctlseqs_match_pattern( + struct ctlseqs_matcher const *matcher, + struct ctlseqs_match_args const *args +) { struct ctlseqs_trie_node const *old_node, empty_node = { 0 }; - struct ctlseqs_match_ctx match_stack[matcher->match_stack_size], match_ctx = { + struct ctlseqs_match_ctx match_stack[matcher->match_stack_size]; + struct ctlseqs_match_ctx match_ctx = { .node = matcher == NULL ? &empty_node : &matcher->root, .seq = args->seq + 1, .result = args->result + (args->save_seq ? 2 : 0), @@ -303,13 +357,14 @@ ctlseqs_match_pattern(struct ctlseqs_matcher const *matcher, struct ctlseqs_matc while (true) { match_ctx.value = match_ctx.node->value; if (match_ctx.value == -1) { - match_character: - match_ctx.node = match_ctx.node->children[(unsigned)match_ctx.seq++[0]]; + match_character: + match_ctx.node + = match_ctx.node->children[(unsigned)match_ctx.seq++[0]]; if (match_ctx.node == NULL) { break; } } else if (match_ctx.value < -1) { - match_placeholder: + match_placeholder: old_node = match_ctx.node; match_ctx.node = match_ctx.node->children[-match_ctx.value]; struct ctlseqs_trie_node *next_node = match_ctx.node->next; @@ -319,7 +374,11 @@ ctlseqs_match_pattern(struct ctlseqs_matcher const *matcher, struct ctlseqs_matc .seq = match_ctx.seq, .result = match_ctx.result, }; - match_ctx.seq = ctlseqs_fetch_value(match_ctx.seq, -match_ctx.value, &match_ctx.result); + match_ctx.seq = ctlseqs_fetch_value( + match_ctx.seq, + -match_ctx.value, + &match_ctx.result + ); if (match_ctx.seq == NULL) { break; } @@ -340,8 +399,10 @@ ctlseqs_match_pattern(struct ctlseqs_matcher const *matcher, struct ctlseqs_matc } ctlseqs_hot static inline ssize_t -ctlseqs_do_match(struct ctlseqs_matcher const *matcher, struct ctlseqs_match_args *args) -{ +ctlseqs_do_match( + struct ctlseqs_matcher const *matcher, + struct ctlseqs_match_args *args +) { ssize_t retval = CTLSEQS_PARTIAL; char const *seq = args->seq; size_t idx, len = args->seq_len; @@ -374,8 +435,10 @@ ctlseqs_do_match(struct ctlseqs_matcher const *matcher, struct ctlseqs_match_arg } ctlseqs_hot static ssize_t -ctlseqs_reader_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher) -{ +ctlseqs_reader_match( + struct ctlseqs_reader *reader, + struct ctlseqs_matcher const *matcher +) { struct ctlseqs_match_args args = { .seq = reader->rbuf + reader->buf_start, .seq_len = reader->buf_end - reader->buf_start, @@ -387,17 +450,25 @@ ctlseqs_reader_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const ssize_t retval = ctlseqs_do_match(matcher, &args); if (retval == CTLSEQS_PARTIAL) { reader->last_idx = args.result_idx; - if (ctlseqs_unlikely(reader->buf_start + args.result_idx == reader->readlen)) { + if (ctlseqs_unlikely( + reader->buf_start + args.result_idx == reader->readlen + )) { // Buffer is full but a match is still pending. - // This may happen when the reader's maxlen option is not large enough to hold a sequence, + // This may happen when the reader's maxlen option is not + // large enough to hold a sequence, // or when the the sequences are produced faster than consumed. if (reader->buf_start > reader->readlen / 2) { - memcpy(reader->rbuf, reader->rbuf + reader->buf_start, args.result_idx); + memcpy( + reader->rbuf, + reader->rbuf + reader->buf_start, + args.result_idx + ); reader->buf_start = 0; reader->buf_end = args.result_idx; } else { - // We could memmove() here, but having a buffer no larger than twice the size of a sequence - // is hardly what a normal program would desire. + // We could memmove() here, but having a buffer no larger than + // twice the size of a sequence is hardly what a normal program + // would desire. retval = CTLSEQS_NOMEM; } } @@ -409,7 +480,11 @@ ctlseqs_reader_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const reader->buf_end = 0; } } - reader->state = args.state >= ctlseqs_state_done ? ctlseqs_state_none : args.state; + if (args.state >= ctlseqs_state_done) { + reader->state = ctlseqs_state_none; + } else { + reader->state = args.state; + } return retval; } @@ -428,10 +503,13 @@ ctlseqs_matcher_init() } int -ctlseqs_matcher_config(struct ctlseqs_matcher *matcher, struct ctlseqs_matcher_options const *options) -{ +ctlseqs_matcher_config( + struct ctlseqs_matcher *matcher, + struct ctlseqs_matcher_options const *options +) { size_t node_idx = 0, max_format_size = 0; - struct ctlseqs_trie_node *node_pool = matcher->node_pools[matcher->pool_idx]; + struct ctlseqs_trie_node *node_pool + = matcher->node_pools[matcher->pool_idx]; matcher->root = (struct ctlseqs_trie_node) { .value = -1 }; for (size_t i = 0; i < options->npatterns; ++i) { char const *pattern = options->patterns[i]; @@ -452,10 +530,14 @@ ctlseqs_matcher_config(struct ctlseqs_matcher *matcher, struct ctlseqs_matcher_o continue; } if (ctlseqs_unlikely(++node_idx >= matcher->pool_size)) { - if (ctlseqs_unlikely(matcher->pool_idx >= CTLSEQS_TRIE_NODE_POOL_MAX_NUM - 1)) { + if (ctlseqs_unlikely( + matcher->pool_idx >= CTLSEQS_TRIE_NODE_POOL_MAX_NUM - 1 + )) { return CTLSEQS_NOMEM; } - node_pool = malloc(sizeof(struct ctlseqs_trie_node) * matcher->pool_size * 2); + node_pool = malloc( + sizeof(struct ctlseqs_trie_node) * matcher->pool_size * 2 + ); if (ctlseqs_unlikely(node_pool == NULL)) { return CTLSEQS_NOMEM; } @@ -464,16 +546,23 @@ ctlseqs_matcher_config(struct ctlseqs_matcher *matcher, struct ctlseqs_matcher_o matcher->pool_size *= 2; } old_node->children[ch] = node = node_pool + node_idx; + ssize_t placeholder; + if (ch < ctlseqs_ph_begin || ch >= ctlseqs_ph_end) { + placeholder = 0; + } else { + placeholder = ch; + } *node = (struct ctlseqs_trie_node) { - .value = -1, // Value -1 indicates that there's no match on current node. - .placeholder = ch < ctlseqs_ph_begin || ch >= ctlseqs_ph_end ? 0 : ch, + // Value -1 indicates that there's no match on current node. + .value = -1, + .placeholder = placeholder, }; - if (node->placeholder == 0) { + if (placeholder == 0) { continue; } if (old_node->value < -1) { - // Node with multiple placeholders contains negated offset of the child node - // which is the head of the linked list. + // Node with multiple placeholders contains negated offset of + // the child node which is the head of the linked list. node->next = old_node->children[-old_node->value]; } old_node->value = -ch; @@ -484,8 +573,12 @@ ctlseqs_matcher_config(struct ctlseqs_matcher *matcher, struct ctlseqs_matcher_o } ctlseqs_hot ssize_t -ctlseqs_match(struct ctlseqs_matcher const *matcher, char const *str, size_t str_len, union ctlseqs_value *result) -{ +ctlseqs_match( + struct ctlseqs_matcher const *matcher, + char const *str, + size_t str_len, + union ctlseqs_value *result +) { struct ctlseqs_match_args args = { .seq = str, .seq_len = str_len, @@ -493,7 +586,7 @@ ctlseqs_match(struct ctlseqs_matcher const *matcher, char const *str, size_t str .save_seq = true, }; ssize_t retval; - try_match: + try_match: retval = ctlseqs_do_match(matcher, &args); if (retval == CTLSEQS_NOSEQ) { size_t result_len = args.result[0].len; @@ -507,8 +600,9 @@ ctlseqs_match(struct ctlseqs_matcher const *matcher, char const *str, size_t str } ctlseqs_cold void -ctlseqs_matcher_free(struct ctlseqs_matcher *matcher) -{ +ctlseqs_matcher_free( + struct ctlseqs_matcher *matcher +) { if (ctlseqs_likely(matcher != NULL)) { for (size_t idx = 1; idx <= matcher->pool_idx; ++idx) { free(matcher->node_pools[idx]); @@ -528,8 +622,10 @@ ctlseqs_reader_init() } int -ctlseqs_reader_config(struct ctlseqs_reader *reader, struct ctlseqs_reader_options const *options) -{ +ctlseqs_reader_config( + struct ctlseqs_reader *reader, + struct ctlseqs_reader_options const *options +) { size_t const readlen = options->maxlen; if (reader->readlen != readlen) { if (readlen < reader->buf_end) { @@ -553,8 +649,11 @@ ctlseqs_reader_config(struct ctlseqs_reader *reader, struct ctlseqs_reader_optio } ctlseqs_hot ssize_t -ctlseqs_read(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher, int timeout) -{ +ctlseqs_read( + struct ctlseqs_reader *reader, + struct ctlseqs_matcher const *matcher, + int timeout +) { ssize_t result; // Whether we have read more than we could match in the preview call. if (reader->state == ctlseqs_state_none && reader->buf_start != 0) { @@ -571,14 +670,20 @@ ctlseqs_read(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matche } result = ctlseqs_do_read(reader); if (ctlseqs_unlikely(result < 0)) { - return reader->state == ctlseqs_state_none ? result : CTLSEQS_PARTIAL; + if (reader->state == ctlseqs_state_none) { + return result; + } else { + return CTLSEQS_PARTIAL; + } } return ctlseqs_reader_match(reader, matcher); } void -ctlseqs_purge(struct ctlseqs_reader *reader, size_t nbytes) -{ +ctlseqs_purge( + struct ctlseqs_reader *reader, + size_t nbytes +) { if (ctlseqs_unlikely(nbytes == 0)) { return; } @@ -592,8 +697,9 @@ ctlseqs_purge(struct ctlseqs_reader *reader, size_t nbytes) } ctlseqs_cold void -ctlseqs_reader_free(struct ctlseqs_reader *reader) -{ +ctlseqs_reader_free( + struct ctlseqs_reader *reader +) { if (ctlseqs_likely(reader != NULL)) { free(reader->rbuf); free(reader); diff --git a/tests/Makefile.am b/tests/Makefile.am index 7f600f7..f01b404 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,12 +7,12 @@ # AUTOMAKE_OPTIONS = dejagnu -AM_CPPFLAGS = -I$(top_srcdir)/include EXTRA_DIST = ctlseqs/*.exp init.exp -noinst_PROGRAMS = tcsgrep -tcsgrep_SOURCES = tcsgrep.c -tcsgrep_LDADD = $(top_builddir)/src/libctlseqs.la +noinst_PROGRAMS = tcsgrep +tcsgrep_CPPFLAGS = -I$(top_srcdir)/include +tcsgrep_SOURCES = tcsgrep.c +tcsgrep_LDADD = $(top_builddir)/src/libctlseqs.la -RUNTESTDEFAULTFLAGS = TCSGREP_BIN=$(srcdir)/tcsgrep +RUNTESTDEFAULTFLAGS = TCSGREP_BIN=$(builddir)/tcsgrep EXTRA_DEJAGNU_SITE_CONFIG = $(srcdir)/init.exp diff --git a/tests/ctlseqs/match.exp b/tests/ctlseqs/match.exp index fbeb771..27cb1b9 100644 --- a/tests/ctlseqs/match.exp +++ b/tests/ctlseqs/match.exp @@ -12,16 +12,19 @@ set timeout 2 set n1 [ random_int ] set n2 [ random_int ] set n3 [ random_int ] +set n1_len [ string length $n1 ] -set input { } -lappend input "$CSI$n1;${n2}H" -lappend input "$DCS$n1;$n2|$n3$ST" -lappend input "$CSIerr_file, "%s: [error] %s.\n", ctx->prog_name, msg); } static inline bool -parse_int(char const *str, int *dest) -{ +parse_int( + char const *str, + int *dest +) { errno = 0; unsigned long result = strtoul(str, NULL, 10); if (errno || result > 4096) { @@ -92,8 +96,10 @@ parse_int(char const *str, int *dest) } static inline void -print_char(struct tcsgrep_ctx const *ctx, int ch) -{ +print_char( + struct tcsgrep_ctx const *ctx, + int ch +) { static char const *ascii_table[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", @@ -114,8 +120,12 @@ print_char(struct tcsgrep_ctx const *ctx, int ch) } static void -print_generic_seq(struct tcsgrep_ctx const *ctx, char const *header, union ctlseqs_value const *result, bool newline) -{ +print_generic_seq( + struct tcsgrep_ctx const *ctx, + char const *header, + union ctlseqs_value const *result, + bool newline +) { size_t length = result[0].len; char const *seq = result[1].str; fprintf(ctx->out_file, "%s %zu", header, length); @@ -129,9 +139,9 @@ print_generic_seq(struct tcsgrep_ctx const *ctx, char const *header, union ctlse static void print_matching_seq( - struct tcsgrep_ctx const *ctx, + struct tcsgrep_ctx const *ctx, struct tcsgrep_sequence const *seq, - union ctlseqs_value const *result, + union ctlseqs_value const *result, bool verbose ) { if (verbose) { @@ -148,7 +158,8 @@ print_matching_seq( fprintf(ctx->out_file, " %lu", result[idx].num); break; case 0x10: // CTLSEQS_PH_STR - fprintf(ctx->out_file, " %.*s", (int)result[idx].len, result[idx + 1].str); + fprintf(ctx->out_file, " %.*s", + (int)result[idx].len, result[idx + 1].str); break; case 0x0f: // CTLSEQS_PH_NUMS for (size_t i = 1; i <= result[idx].len; ++i) { @@ -161,8 +172,10 @@ print_matching_seq( } int -main(int argc, char **argv) -{ +main( + int argc, + char **argv +) { struct tcsgrep_ctx ctx = { .prog_name = argv[0], .out_file = stdout, @@ -175,28 +188,29 @@ main(int argc, char **argv) int opt; while (-1 != (opt = getopt(argc, argv, "t:l:pv"))) { switch (opt) { - case 't': - if (!parse_int(optarg, &ctx.timeout)) { - print_error(&ctx, "invalid timeout option"); - return 1; - } - break; - case 'l': - if (!parse_int(optarg, &ctx.limit)) { - print_error(&ctx, "invalid limit option"); - return 1; - } - break; - case 'p': - ctx.purge_long_seqs = true; - break; - case 'v': - ctx.verbose = true; - break; - case '?': - default: - fprintf(ctx.out_file, "%s\n", "Usage: tcsgrep [-t timeout] [-l limit] [-pv]"); + case 't': + if (!parse_int(optarg, &ctx.timeout)) { + print_error(&ctx, "invalid timeout option"); return 1; + } + break; + case 'l': + if (!parse_int(optarg, &ctx.limit)) { + print_error(&ctx, "invalid limit option"); + return 1; + } + break; + case 'p': + ctx.purge_long_seqs = true; + break; + case 'v': + ctx.verbose = true; + break; + case '?': + default: + fprintf(ctx.out_file, "%s\n", + "Usage: tcsgrep [-t timeout] [-l limit] [-pv]"); + return 1; } } @@ -257,7 +271,8 @@ main(int argc, char **argv) DEFSEQ(SU, CTLSEQS_PH_NUM), DEFSEQ(XTSMGRAPHICS, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUMS), DEFSEQ(SD, CTLSEQS_PH_NUM), - DEFSEQ(XTHIMOUSE, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(XTHIMOUSE, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(XTRMTITLE, CTLSEQS_PH_STR), DEFSEQ(ECH, CTLSEQS_PH_NUM), DEFSEQ(CBT, CTLSEQS_PH_NUM), @@ -293,34 +308,43 @@ main(int argc, char **argv) DEFSEQ(DECSCA, CTLSEQS_PH_NUM), DEFSEQ(DECSTBM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(XTRESTORE, CTLSEQS_PH_NUMS), - DEFSEQ(DECCARA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECCARA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ_NOARGS(SCOSC), DEFSEQ(DECSLRM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(XTSAVE, CTLSEQS_PH_NUMS), DEFSEQ(XTWINOPS, CTLSEQS_PH_NUMS), DEFSEQ(XTSMTITLE, CTLSEQS_PH_NUMS), DEFSEQ(DECSWBV, CTLSEQS_PH_NUM), - DEFSEQ(DECRARA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECRARA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ_NOARGS(SCORC), DEFSEQ(DECSMBV, CTLSEQS_PH_NUM), - DEFSEQ(DECCRA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, - CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECCRA, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECRQPSR, CTLSEQS_PH_NUM), - DEFSEQ(DECEFR, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECEFR, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECREQTPARM, CTLSEQS_PH_NUM), - DEFSEQ(DECEFR, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECEFR, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECREQTPARM, CTLSEQS_PH_NUM), DEFSEQ(DECSACE, CTLSEQS_PH_NUM), - DEFSEQ(DECFRA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), - DEFSEQ(XTCHECKSUM, CTLSEQS_PH_NUM), - DEFSEQ(DECRQCRA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + DEFSEQ(DECFRA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(XTCHECKSUM, CTLSEQS_PH_NUM), + DEFSEQ(DECRQCRA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECELR, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), - DEFSEQ(DECERA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECERA, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECSLE, CTLSEQS_PH_NUMS), DEFSEQ(XTPUSHSGR, CTLSEQS_PH_NUMS), - DEFSEQ(DECSERA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), - DEFSEQ(XTREPORTSGR, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(DECSERA, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(XTREPORTSGR, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(DECSCPP, CTLSEQS_PH_NUM), DEFSEQ_NOARGS(DECRQLP), DEFSEQ(DECSNLS, CTLSEQS_PH_NUM), @@ -332,7 +356,8 @@ main(int argc, char **argv) DEFSEQ(RESP_XTGETXRES, CTLSEQS_PH_NUM, CTLSEQS_PH_STR), DEFSEQ(RESP_XTGETTCAP, CTLSEQS_PH_NUM, CTLSEQS_PH_STR), DEFSEQ(RESP_PRIMARY_DA, CTLSEQS_PH_NUMS), - DEFSEQ(RESP_SECONDARY_DA, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(RESP_SECONDARY_DA, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(RESP_DECXCPR, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ(RESP_DSR, CTLSEQS_PH_NUMS), DEFSEQ(RESP_DECRQM_ANSI, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), @@ -341,7 +366,8 @@ main(int argc, char **argv) DEFSEQ(RESP_DECCIR, CTLSEQS_PH_STR), DEFSEQ(RESP_DECTABSR, CTLSEQS_PH_STR), DEFSEQ(RESP_DECRQCRA, CTLSEQS_PH_NUM, CTLSEQS_PH_STR), - DEFSEQ(RESP_DECRQLP, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), + DEFSEQ(RESP_DECRQLP, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, + CTLSEQS_PH_NUM, CTLSEQS_PH_NUM), DEFSEQ_NOARGS(KEY_UP), DEFSEQ_NOARGS(KEY_DOWN), DEFSEQ_NOARGS(KEY_RIGHT), @@ -413,50 +439,50 @@ main(int argc, char **argv) while (true) { ssize_t retval = ctlseqs_read(reader, matcher, ctx.timeout); switch (retval) { - case CTLSEQS_ERROR: - print_error(&ctx, "unexpected error"); + case CTLSEQS_ERROR: + print_error(&ctx, "unexpected error"); + status = 1; + goto terminate; + case CTLSEQS_TIMEOUT: + fprintf(ctx.out_file, "TIMEOUT\n"); + status = 1; + goto terminate; + case CTLSEQS_INTR: + fprintf(ctx.out_file, "INTR\n"); + break; + case CTLSEQS_EOF: + fprintf(ctx.out_file, "EOF\n"); + goto terminate; + case CTLSEQS_PARTIAL: + if (ctx.verbose) { + print_generic_seq(&ctx, "PARTIAL", result, true); + } + break; + case CTLSEQS_NOMATCH: + print_generic_seq(&ctx, "NOMATCH", result, true); + break; + case CTLSEQS_NOMEM: + print_generic_seq(&ctx, "NOMEM", result, true); + if (ctx.purge_long_seqs) { + ctlseqs_purge(reader, result[0].len); + break; + } else { status = 1; goto terminate; - case CTLSEQS_TIMEOUT: - fprintf(ctx.out_file, "TIMEOUT\n"); - status = 1; + } + case CTLSEQS_NOSEQ: + print_generic_seq(&ctx, "NOSEQ", result, true); + if (!ctx.not_tty && result[1].str[0] == 0x04) { goto terminate; - case CTLSEQS_INTR: - fprintf(ctx.out_file, "INTR\n"); - break; - case CTLSEQS_EOF: - fprintf(ctx.out_file, "EOF\n"); - goto terminate; - case CTLSEQS_PARTIAL: - if (ctx.verbose) { - print_generic_seq(&ctx, "PARTIAL", result, true); - } - break; - case CTLSEQS_NOMATCH: - print_generic_seq(&ctx, "NOMATCH", result, true); - break; - case CTLSEQS_NOMEM: - print_generic_seq(&ctx, "NOMEM", result, true); - if (ctx.purge_long_seqs) { - ctlseqs_purge(reader, result[0].len); - break; - } else { - status = 1; - goto terminate; - } - case CTLSEQS_NOSEQ: - print_generic_seq(&ctx, "NOSEQ", result, true); - if (!ctx.not_tty && result[1].str[0] == 0x04) { - goto terminate; - } - break; - default: - print_matching_seq(&ctx, &seqs[retval], result, ctx.verbose); - break; + } + break; + default: + print_matching_seq(&ctx, &seqs[retval], result, ctx.verbose); + break; } } - terminate: + terminate: ctlseqs_matcher_free(matcher); ctlseqs_reader_free(reader); if (!ctx.not_tty) {