From 42ff23420419e3839fa064a7490c9216d94896a7 Mon Sep 17 00:00:00 2001 From: Martin Lund Date: Sat, 27 Apr 2024 15:22:41 +0200 Subject: [PATCH] Add hexN output mode Adds support for hexN mode where N is a number in the range 1 to 4096 which defines how many hex values will be printed before a line break. In short, it defines the width of the hex output. In this mode, if timestamps are enabled they will be added to each hex line. --- README.md | 2 +- man/tio.1.in | 9 +++-- src/options.c | 66 +++++++++++++++++++++++++++++++++-- src/options.h | 1 + src/tty.c | 95 ++++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 151 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index a196fd1..445897d 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Options: -n, --no-reconnect Do not reconnect -e, --local-echo Enable local echo --input-mode normal|hex|line Select input mode (default: normal) - --output-mode normal|hex Select output mode (default: normal) + --output-mode normal|hex|hexN Select output mode (default: normal, N <= 4096) -t, --timestamp Enable line timestamp --timestamp-format Set timestamp format (default: 24hour) --timestamp-timeout Set timestamp timeout (default: 200) diff --git a/man/tio.1.in b/man/tio.1.in index 4507d2f..75d05bb 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -248,9 +248,14 @@ editing feature supported in this mode is backspace. Default value is "normal". .TP -.BR " \-\-output\-mode " normal|hex +.BR " \-\-output\-mode " normal|hex|hexN -Set output mode. In hex mode each incoming byte is printed out as a 1 byte hex value. +Set output mode. + +In hex mode each incoming byte is printed out as a 1 byte hex value. + +In hexN mode, N is a number less than or equal to 4096 which defines how many +hex values will be printed before a line break. Default value is "normal". diff --git a/src/options.c b/src/options.c index 73c5bc8..f8a77da 100644 --- a/src/options.c +++ b/src/options.c @@ -20,6 +20,7 @@ */ #include "config.h" +#include #include #include #include @@ -41,6 +42,8 @@ #include "log.h" #include "script.h" +#define HEX_N_VALUE_MAX 4096 + enum opt_t { OPT_NONE, @@ -114,6 +117,7 @@ struct option_t option = .exclude_devices = NULL, .exclude_drivers = NULL, .exclude_tids = NULL, + .hex_n_value = 0, }; void print_help(char *argv[]) @@ -140,7 +144,7 @@ void print_help(char *argv[]) printf(" -n, --no-reconnect Do not reconnect\n"); printf(" -e, --local-echo Enable local echo\n"); printf(" --input-mode normal|hex|line Select input mode (default: normal)\n"); - printf(" --output-mode normal|hex Select output mode (default: normal)\n"); + printf(" --output-mode normal|hex|hexN Select output mode (default: normal, N <= %d)\n", HEX_N_VALUE_MAX); printf(" -t, --timestamp Enable line timestamp\n"); printf(" --timestamp-format Set timestamp format (default: 24hour)\n"); printf(" --timestamp-timeout Set timestamp timeout (default: 200)\n"); @@ -268,6 +272,61 @@ void line_pulse_duration_option_parse(const char *arg) free(buffer); } +// Function to parse the input string +int parse_hexN_string(const char *input_string) +{ + regmatch_t match[2]; // One for entire match, one for the optional N + int n_value = 0; + regex_t regex; + int ret; + + // Compile the regular expression to match "hex" and optionally capture N + ret = regcomp(®ex, "^hex([0-9]+)?$", REG_EXTENDED); + if (ret) + { + tio_error_printf("Could not compile regex\n"); + exit(EXIT_FAILURE); + } + + // Execute the regular expression + ret = regexec(®ex, input_string, 2, match, 0); + if (!ret) + { + // If there is a match, extract the N value if present + if (match[1].rm_so != -1) + { + char n_value_str[32]; // Assume max 32 digits for the numerical value + strncpy(n_value_str, input_string + match[1].rm_so, match[1].rm_eo - match[1].rm_so); + n_value_str[match[1].rm_eo - match[1].rm_so] = '\0'; // Null-terminate the string + n_value = atoi(n_value_str); + + if ((n_value > HEX_N_VALUE_MAX) || (n_value == 0)) + { + n_value = -1; + } + } + else + { + n_value = 0; + } + } + else if (ret == REG_NOMATCH) + { + n_value = -1; + } + else + { + char msgbuf[100]; + regerror(ret, ®ex, msgbuf, sizeof(msgbuf)); + tio_error_printf("Regex match failed: %s\n", msgbuf); + exit(EXIT_FAILURE); + } + + regfree(®ex); + + return n_value; +} + input_mode_t input_mode_option_parse(const char *arg) { if (strcmp("normal", arg) == 0) @@ -291,12 +350,15 @@ input_mode_t input_mode_option_parse(const char *arg) output_mode_t output_mode_option_parse(const char *arg) { + int n = 0; + if (strcmp("normal", arg) == 0) { return OUTPUT_MODE_NORMAL; } - else if (strcmp("hex", arg) == 0) + else if ((n = parse_hexN_string(arg)) != -1) { + option.hex_n_value = n; return OUTPUT_MODE_HEX; } else diff --git a/src/options.h b/src/options.h index 48048cb..d5a054b 100644 --- a/src/options.h +++ b/src/options.h @@ -94,6 +94,7 @@ struct option_t const char *exclude_devices; const char *exclude_drivers; const char *exclude_tids; + int hex_n_value; }; extern struct option_t option; diff --git a/src/tty.c b/src/tty.c index cebe7f5..6be7581 100644 --- a/src/tty.c +++ b/src/tty.c @@ -2086,7 +2086,7 @@ int tty_connect(void) char line_buffer[BUFSIZ] = {}; static bool first = true; int status; - bool next_timestamp = false; + bool do_timestamp = false; char* now = NULL; unsigned int line_index = 0; static char previous_char[2] = {}; @@ -2128,7 +2128,7 @@ int tty_connect(void) if (option.timestamp) { - next_timestamp = true; + do_timestamp = true; } /* Manage print output mode */ @@ -2260,7 +2260,7 @@ int tty_connect(void) rx_total += bytes_read; // Manage timeout based timestamping in hex mode - if (option.output_mode == OUTPUT_MODE_HEX) + if ((option.output_mode == OUTPUT_MODE_HEX) && (option.hex_n_value == 0)) { if (option.timestamp != TIMESTAMP_NONE) { @@ -2276,7 +2276,7 @@ int tty_connect(void) { log_printf("\r\n[%s] ", now); } - next_timestamp = false; + do_timestamp = false; } } tval_before = tval_now; @@ -2286,24 +2286,85 @@ int tty_connect(void) /* Process input byte by byte */ for (int i=0; i 0) + { + static bool first = true; + if ((count % option.hex_n_value) == 0) + { + if (option.timestamp != TIMESTAMP_NONE) + { + now = timestamp_current_time(); + if (first) + { + ansi_printf_raw("[%s] ", now); + if (option.log) + { + log_printf("[%s] ", now); + } + first = false; + } + else + { + ansi_printf_raw("\r\n[%s] ", now); + if (option.log) + { + log_printf("\n[%s] ", now); + } + } + } + else + { + if (first) + { + // Do nothing + } + else + { + putchar('\r'); + putchar('\n'); + + if (option.log) + { + log_putc('\n'); + } + first = false; + } + } + } + } + count++; + break; + + default: + tio_error_printf("Unknown outut mode"); + exit(EXIT_FAILURE); + break; } /* Convert MSB to LSB bit order */ @@ -2324,7 +2385,7 @@ int tty_connect(void) print('\n'); if (option.timestamp) { - next_timestamp = true; + do_timestamp = true; } } else if ((input_char == '\f') && (map_i_ff_escc) && (!map_o_msblsb)) @@ -2350,7 +2411,7 @@ int tty_connect(void) if (input_char == '\n' && option.timestamp) { - next_timestamp = true; + do_timestamp = true; } } }