From b2aafd696b90a0e6ba68becb5038c070e72f0ebe Mon Sep 17 00:00:00 2001 From: Martin Lund Date: Sun, 5 Nov 2017 20:52:12 +0100 Subject: [PATCH] Add special character map feature Add a --map option which allows to map special characters, in particular CR and NL characters which are used in various combinations on varios platforms. --- README | 1 + man/tio.1 | 22 ++++++++++++++++++++++ src/bash-completion/tio.in | 5 +++++ src/include/tio/options.h | 1 + src/options.c | 12 ++++++++++-- src/tty.c | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/README b/README index fd62901..0491598 100644 --- a/README +++ b/README @@ -30,6 +30,7 @@ -o, --output-delay Output delay (default: 0) -n, --no-autoconnect Disable automatic connect -l, --log Log to file + -m, --map Map special characters -v, --version Display version -h, --help Display help diff --git a/man/tio.1 b/man/tio.1 index 6cfea2a..4e122b9 100644 --- a/man/tio.1 +++ b/man/tio.1 @@ -55,6 +55,28 @@ option is provided, tio will exit if the device is not present or an established .BR \-l ", " "\-\-log " \fI Log to file. + +.TP +.BR \-m ", " "\-\-map " \fI + +Map (replace, translate) special characters on input or output. The following mapping flags are supported: + +.RS +.TP 8n +.IP "\fBINLCR" +Translate NL to CR on input. +.IP "\fBIGNCR" +Ignore carriage return on input. +.IP "\fBICRNL" +Translate carriage return to newline on input (unless IGNCR is set). +.IP "\fBONLCR" +Map NL to CR-NL on output. +.IP "\fBOCRNL" +Map CR to NL on output. +.P +If defining more than one flag, the flags must be comma separated. +.RE + .TP .BR \-v ", " \-\-version diff --git a/src/bash-completion/tio.in b/src/bash-completion/tio.in index 0f8dde4..431b1cc 100644 --- a/src/bash-completion/tio.in +++ b/src/bash-completion/tio.in @@ -18,6 +18,7 @@ _tio() -o --output-delay \ -n --no-autoconnect \ -l --log \ + -m --map \ -v --version \ -h --help" @@ -56,6 +57,10 @@ _tio() COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; + -m | --map) + COMPREPLY=( $(compgen -W "INLCR IGNCR ICRNL ONLCR OCRNL" -- ${cur}) ) + return 0 + ;; -v | --version) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/src/include/tio/options.h b/src/include/tio/options.h index 15f3cf7..b41f340 100644 --- a/src/include/tio/options.h +++ b/src/include/tio/options.h @@ -40,6 +40,7 @@ struct option_t bool no_autoconnect; bool log; const char *log_filename; + const char *map; }; extern struct option_t option; diff --git a/src/options.c b/src/options.c index 67275c3..fa47f60 100644 --- a/src/options.c +++ b/src/options.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,8 @@ struct option_t option = 0, // No output delay false, // No autoconnect false, // No log - "" // Log filename + "", // Log filename + "" // Map string }; void print_help(char *argv[]) @@ -60,6 +62,7 @@ void print_help(char *argv[]) printf(" -o, --output-delay Output delay (default: 0)\n"); printf(" -n, --no-autoconnect Disable automatic connect\n"); printf(" -l, --log Log to file\n"); + printf(" -m, --map Map special characters\n"); printf(" -v, --version Display version\n"); printf(" -h, --help Display help\n"); printf("\n"); @@ -105,6 +108,7 @@ void parse_options(int argc, char *argv[]) {"output-delay", required_argument, 0, 'o'}, {"no-autoconnect", no_argument, 0, 'n'}, {"log", required_argument, 0, 'l'}, + {"map", required_argument, 0, 'm'}, {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0 } @@ -114,7 +118,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:nl:vh", long_options, &option_index); + c = getopt_long(argc, argv, "b:d:f:s:p:o:nl:m:vh", long_options, &option_index); /* Detect the end of the options */ if (c == -1) @@ -165,6 +169,10 @@ void parse_options(int argc, char *argv[]) option.log_filename = optarg; break; + case 'm': + option.map = optarg; + break; + case 'v': printf("tio v%s\n", VERSION); printf("Copyright (c) 2014-2017 Martin Lund\n"); diff --git a/src/tty.c b/src/tty.c index a8b08b8..9cf88fd 100644 --- a/src/tty.c +++ b/src/tty.c @@ -112,6 +112,8 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c tio_printf(" Stopbits: %d", option.stopbits); tio_printf(" Parity: %s", option.parity); tio_printf(" Output delay: %d", option.output_delay); + if (option.map[0] != 0) + tio_printf(" Map flags: %s", option.map); if (option.log) tio_printf(" Log file: %s", option.log_filename); break; @@ -209,6 +211,9 @@ void stdout_restore(void) void tty_configure(void) { + bool token_found = true; + char *token = NULL; + char *buffer; int status; speed_t baudrate; @@ -335,6 +340,39 @@ void tty_configure(void) /* Control characters */ tio.c_cc[VTIME] = 0; // Inter-character timer unused tio.c_cc[VMIN] = 1; // Blocking read until 1 character received + + /* Configure any specified input or output mappings */ + + buffer = strdup(option.map); + while (token_found == true) + { + if (token == NULL) + token = strtok(buffer,","); + else + token = strtok(NULL, ","); + + if (token != NULL) + { + if (strcmp(token,"INLCR") == 0) + tio.c_iflag |= INLCR; + else if (strcmp(token,"IGNCR") == 0) + tio.c_iflag |= IGNCR; + else if (strcmp(token,"ICRNL") == 0) + tio.c_iflag |= ICRNL; + else if (strcmp(token,"ONLCR") == 0) + tio.c_oflag |= ONLCR; + else if (strcmp(token,"OCRNL") == 0) + tio.c_oflag |= OCRNL; + else + { + printf("Error: Unknown mapping flag %s\n", token); + exit(EXIT_FAILURE); + } + } + else + token_found = false; + } + free(buffer); } void tty_wait_for_device(void)