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.
This commit is contained in:
Martin Lund 2024-04-27 15:22:41 +02:00
parent 4113a072c2
commit 42ff234204
5 changed files with 151 additions and 22 deletions

View file

@ -20,6 +20,7 @@
*/
#include "config.h"
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
@ -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 <format> Set timestamp format (default: 24hour)\n");
printf(" --timestamp-timeout <ms> 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(&regex, "^hex([0-9]+)?$", REG_EXTENDED);
if (ret)
{
tio_error_printf("Could not compile regex\n");
exit(EXIT_FAILURE);
}
// Execute the regular expression
ret = regexec(&regex, 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, &regex, msgbuf, sizeof(msgbuf));
tio_error_printf("Regex match failed: %s\n", msgbuf);
exit(EXIT_FAILURE);
}
regfree(&regex);
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

View file

@ -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;

View file

@ -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<bytes_read; i++)
{
static unsigned long count = 0;
input_char = input_buffer[i];
/* Print timestamp on new line if enabled */
if (option.output_mode == OUTPUT_MODE_NORMAL)
/* Handle timestamps */
switch (option.output_mode)
{
if ((next_timestamp && input_char != '\n' && input_char != '\r'))
{
now = timestamp_current_time();
if (now)
case OUTPUT_MODE_NORMAL:
// Support timestamp per line
if ((do_timestamp && input_char != '\n' && input_char != '\r'))
{
ansi_printf_raw("[%s] ", now);
if (option.log)
now = timestamp_current_time();
if (now)
{
log_printf("[%s] ", now);
ansi_printf_raw("[%s] ", now);
if (option.log)
{
log_printf("[%s] ", now);
}
do_timestamp = false;
}
next_timestamp = false;
}
}
break;
case OUTPUT_MODE_HEX:
// Support hexN mode
if (option.hex_n_value > 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;
}
}
}