diff --git a/src/include/tio/log.h b/src/include/tio/log.h index 41b5103..75fcb45 100644 --- a/src/include/tio/log.h +++ b/src/include/tio/log.h @@ -24,6 +24,7 @@ void log_open(const char *filename); void log_write(char c); +void log_writeline(char *l, int max_line_size, bool esc_strip); void log_close(void); void log_exit(void); diff --git a/src/include/tio/options.h b/src/include/tio/options.h index 1ae1974..946e03d 100644 --- a/src/include/tio/options.h +++ b/src/include/tio/options.h @@ -42,6 +42,7 @@ struct option_t bool local_echo; bool timestamp; const char *log_filename; + bool strip_esc; const char *map; }; diff --git a/src/log.c b/src/log.c index 0bad55d..1a79b9a 100644 --- a/src/log.c +++ b/src/log.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "tio/options.h" #include "tio/print.h" #include "tio/error.h" @@ -40,7 +41,7 @@ void log_open(const char *filename) log_error = true; exit(EXIT_FAILURE); } - setvbuf(fp, NULL, _IONBF, 0); + setvbuf(fp, NULL, _IOLBF, 0); } void log_write(char c) @@ -49,6 +50,75 @@ void log_write(char c) fputc(c, fp); } +#define IS_ESC_INTERMEDIATE_CHAR(c) ((c <= 0x2F) && (c >= 0x20)) +#define IS_ESC_END_CHAR(c) ((c <= 0x7E) && (c >= 0x30)) +#define IS_CSI_END_CHAR(c) ((c <= 0x7E) && (c >= 0x40)) + +static void scan_ctrl_char(char *buf, int length) +{ + int i, j; + size_t len = strnlen(buf, length); + char c; + + i = j = 0; + while (i < len) { + c = buf[i++]; + if (iscntrl(c)) { + switch (c) + { + case 8: /* backspace */ + j--; + break; + + case 13: /* \r */ + break; + + case 27: /* ESC */ + c = buf[i++]; + + if (c == 0x5B) { /* CSI */ + c = buf[i++]; + while (!IS_CSI_END_CHAR(c)) { + c = buf[i++]; + } + } else { + while (!IS_ESC_END_CHAR(c)) { + c = buf[i++]; + } + } + break; + default: + buf[j++] = c; + break; + + } + } else { + buf[j++] = c; + } + } + buf[j] = '\0'; +} + +void log_writeline(char *l, int max_line_size, bool esc_strip) +{ + char *buf = NULL; + + if (fp == NULL) + return; + + if (esc_strip) { + buf = strdup(l); + scan_ctrl_char(buf, max_line_size); + fputs(buf, fp); + free(buf); + } else { + buf = l; + fputs(buf, fp); + } + + fflush(fp); +} + void log_close(void) { if (fp != NULL) diff --git a/src/options.c b/src/options.c index c88582a..53f075f 100644 --- a/src/options.c +++ b/src/options.c @@ -48,6 +48,7 @@ struct option_t option = false, // No local echo false, // No timestamp "", // Log filename + false, // Strip esc charaters from log file "" // Map string }; @@ -67,6 +68,7 @@ void print_help(char *argv[]) printf(" -t, --timestamp Prefix each new line with a timestamp\n"); printf(" -l, --log Log to file\n"); printf(" -m, --map Map special characters\n"); + printf(" -S, --strip-esc Strip esc characters from log file\n"); printf(" -v, --version Display version\n"); printf(" -h, --help Display help\n"); printf("\n"); @@ -117,6 +119,7 @@ void parse_options(int argc, char *argv[]) {"timestamp", no_argument, 0, 't'}, {"log", required_argument, 0, 'l'}, {"map", required_argument, 0, 'm'}, + {"strip-esc", no_argument, 0, 'S'}, {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0 } @@ -126,7 +129,7 @@ void parse_options(int argc, char *argv[]) int option_index = 0; /* Parse argument using getopt_long */ - c = getopt_long(argc, argv, "b:d:f:s:p:o:netl:m:vh", long_options, &option_index); + c = getopt_long(argc, argv, "b:d:f:s:p:o:netl:m:Svh", long_options, &option_index); /* Detect the end of the options */ if (c == -1) @@ -189,6 +192,10 @@ void parse_options(int argc, char *argv[]) option.map = optarg; break; + case 'S': + option.strip_esc = true; + break; + case 'v': printf("tio v%s\n", VERSION); printf("Copyright (c) 2014-2018 Martin Lund\n"); diff --git a/src/tty.c b/src/tty.c index d0569b1..220e631 100644 --- a/src/tty.c +++ b/src/tty.c @@ -44,6 +44,8 @@ #include "tio/log.h" #include "tio/error.h" +#define BUFFER_LEN 4096 + #ifdef HAVE_TERMIOS2 extern int setspeed2(int fd, int baudrate); #endif @@ -60,6 +62,7 @@ static bool map_i_nl_crnl = false; static bool map_o_cr_nl = false; static bool map_o_nl_crnl = false; static bool map_o_del_bs = false; +static char line_buf[BUFFER_LEN]; #define tio_printf(format, args...) \ { \ @@ -616,6 +619,7 @@ int tty_connect(void) int status; time_t next_timestamp = 0; char* now = NULL; + int line_cur = 0; /* Open tty device */ #ifdef __APPLE__ @@ -711,17 +715,7 @@ int tty_connect(void) { now = current_time(); fprintf(stdout, ANSI_COLOR_GRAY "[%s] " ANSI_COLOR_RESET, now); - if (option.log) - { - log_write('['); - while (*now != '\0') - { - log_write(*now); - ++now; - } - log_write(']'); - log_write(' '); - } + line_cur = snprintf(line_buf, BUFFER_LEN, "[%s] " ANSI_COLOR_RESET, now); next_timestamp = 0; } @@ -736,17 +730,27 @@ int tty_connect(void) { /* Print received tty character to stdout */ print(input_char); + + /* Avoid out bound access of line_buf */ + if (line_cur < BUFFER_LEN - 1) + line_buf[line_cur++] = input_char; } fflush(stdout); - /* Write to log */ - if (option.log) - log_write(input_char); - tainted = true; - if (input_char == '\n' && option.timestamp) + if (input_char == '\n' && option.timestamp) { + /* No risk out bound access of line_buf */ + line_buf[line_cur] = '\0'; + + if (option.log && (strlen(line_buf) > 0)) { + bool esc_strip = (option.strip_esc == true); + log_writeline(line_buf, BUFFER_LEN, esc_strip); + } + + line_cur = 0; next_timestamp = time(NULL); + } } else { /* Error reading - device is likely unplugged */