diff --git a/README.md b/README.md index 87bbfe7..6a73437 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ The command-line interface is straightforward as reflected in the output from -L, --list-devices List available serial devices -l, --log Enable log to file --log-file Set log filename + --log-strip Strip control characters and escape sequences -m, --map Map special characters -c, --color 0..255|none|list Colorize tio text (default: 15) -S, --socket Listen on socket diff --git a/man/tio.1.in b/man/tio.1.in index 8534f98..d0a4137 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -93,6 +93,11 @@ Enable log to file. If no filename is provided the filename will be automaticall Set log filename. +.TP +.BR " \-\-log-strip + +Strip control characters and escape sequences from log. + .TP .BR \-m ", " "\-\-map " \fI diff --git a/src/bash-completion/tio.in b/src/bash-completion/tio.in index 3eb9596..06ef729 100644 --- a/src/bash-completion/tio.in +++ b/src/bash-completion/tio.in @@ -19,6 +19,7 @@ _tio() -n --no-autoconnect \ -l --log \ --log-file \ + --log-strip \ -m --map \ -t --timestamp \ --timestamp-format \ @@ -72,6 +73,10 @@ _tio() COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; + -l | --log-strip) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; -m | --map) COMPREPLY=( $(compgen -W "ICRNL IGNCR INLCR INLCRNL OCRNL ODELBS ONLCRNL" -- ${cur}) ) return 0 diff --git a/src/log.c b/src/log.c index 640f834..8faa9c2 100644 --- a/src/log.c +++ b/src/log.c @@ -31,6 +31,10 @@ #include "print.h" #include "error.h" +#define IS_ESC_CSI_INTERMEDIATE_CHAR(c) ((c >= 0x20) && (c <= 0x3F)) +#define IS_ESC_END_CHAR(c) ((c >= 0x30) && (c <= 0x7E)) +#define IS_CTRL_CHAR(c) ((c >= 0x00) && (c <= 0x1F)) + static FILE *fp; static bool log_error = false; @@ -70,11 +74,84 @@ void log_open(const char *filename) setvbuf(fp, NULL, _IONBF, 0); } +bool log_strip(char c) +{ + static char previous_char = 0; + static bool esc_sequence = false; + bool strip = false; + + /* Detect if character should be stripped or not */ + switch (c) + { + case 0x8: + /* Backspace */ + break; + + case 0xa: + /* Line feed */ + /* Reset ESC sequence just in case something went wrong with the + * escape sequence parsing. */ + esc_sequence = false; + break; + + case 0x1b: + /* Escape */ + strip = true; + break; + + case 0x5b: + /* Left bracket */ + if (previous_char == 0x1b) + { + // Start of ESC sequence + esc_sequence = true; + strip = true; + } + break; + + default: + if (IS_CTRL_CHAR(c)) + { + /* Strip ASCII control characters */ + strip = true; + break; + } + else + if ((esc_sequence) && (IS_ESC_CSI_INTERMEDIATE_CHAR(c))) + { + strip = true; + break; + } + else + if ((esc_sequence) && (IS_ESC_END_CHAR(c))) + { + esc_sequence = false; + strip = true; + break; + } + break; + } + + previous_char = c; + + return strip; +} + void log_write(char c) { if (fp != NULL) { - fputc(c, fp); + if (option.log_strip) + { + if (!log_strip(c)) + { + fputc(c, fp); + } + } + else + { + fputc(c, fp); + } } } diff --git a/src/options.c b/src/options.c index 36062bb..35d976d 100644 --- a/src/options.c +++ b/src/options.c @@ -41,6 +41,7 @@ enum opt_t OPT_NONE, OPT_TIMESTAMP_FORMAT, OPT_LOG_FILE, + OPT_LOG_STRIP, }; /* Default options */ @@ -55,9 +56,10 @@ struct option_t option = .output_delay = 0, .no_autoconnect = false, .log = false, + .log_filename = NULL, + .log_strip = false, .local_echo = false, .timestamp = TIMESTAMP_NONE, - .log_filename = NULL, .socket = NULL, .map = "", .color = 15, @@ -82,6 +84,7 @@ void print_help(char *argv[]) printf(" -L, --list-devices List available serial devices\n"); printf(" -l, --log Enable log to file\n"); printf(" --log-file Set log filename\n"); + printf(" --log-strip Strip control characters and escape sequences\n"); printf(" -m, --map Map special characters\n"); printf(" -c, --color 0..255|none|list Colorize tio text (default: 15)\n"); printf(" -S, --socket Listen on socket\n"); @@ -192,6 +195,7 @@ void options_parse(int argc, char *argv[]) {"list-devices", no_argument, 0, 'L' }, {"log", no_argument, 0, 'l' }, {"log-file", required_argument, 0, OPT_LOG_FILE }, + {"log-strip", no_argument, 0, OPT_LOG_STRIP }, {"socket", required_argument, 0, 'S' }, {"map", required_argument, 0, 'm' }, {"color", required_argument, 0, 'c' }, @@ -276,6 +280,10 @@ void options_parse(int argc, char *argv[]) option.log_filename = optarg; break; + case OPT_LOG_STRIP: + option.log_strip = true; + break; + case 'S': option.socket = optarg; break; diff --git a/src/options.h b/src/options.h index 5684d33..cc905bf 100644 --- a/src/options.h +++ b/src/options.h @@ -50,6 +50,7 @@ struct option_t int output_delay; bool no_autoconnect; bool log; + bool log_strip; bool local_echo; enum timestamp_t timestamp; const char *log_filename;