]> git.sur5r.net Git - tio/commitdiff
Imported Upstream version 1.12 upstream/1.12
authorJakob Haufe <sur5r@sur5r.net>
Wed, 18 May 2016 21:16:54 +0000 (23:16 +0200)
committerJakob Haufe <sur5r@sur5r.net>
Wed, 18 May 2016 21:16:54 +0000 (23:16 +0200)
21 files changed:
AUTHORS
ChangeLog
README
configure
configure.ac
man/tio.1
src/Makefile.am
src/Makefile.in
src/error.c [new file with mode: 0644]
src/include/config.h.in
src/include/tio/error.h [new file with mode: 0644]
src/include/tio/log.h
src/include/tio/options.h
src/include/tio/print.h
src/include/tio/time.h
src/include/tio/tty.h
src/log.c
src/main.c
src/options.c
src/time.c
src/tty.c

diff --git a/AUTHORS b/AUTHORS
index d0f5a2668a89467663b2621ca3e8329aad606a53..cf76a655ff483bc1bdee860d57687577b51146da 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,5 +6,6 @@ Jesper Larsen <knorr.jesper@gmail.com>
 Jeppe Ledet-Pedersen <jlp@gomspace.com>
 Jakob Haufe <sur5r@sur5r.net>
 Jakub Wilk <jwilk@jwilk.net>
+Martin Hundeboll <martin@hundeboll.net>
 
 Thanks to everyone who has contributed to this project.
index 983cd3a602acc88368a04c091ed3757f68abdaad..e105ad58dd9f78efb870378fb61da9ba619700df 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-=== tio v1.6 ===
+=== tio v1.12 ===
 
-Changes since tio v1.5:
+Changes since tio v1.11:
 
- * Renamed "gotty" to "tio"
+ * Consolidated command key handling
 
-   Renamed to "tio" because it is shorter and this new name also more
-   precisely reflects what the program is - a simple TTY terminal I/O
-   application.
+ * Moved delay mechanism into separate function
 
-   "tio" can be considered short for terminal I/O or TTY I/O or a
-   combination of the two, whichever you prefer.
+ * Retired obsolete usleep()
 
-   Also, wanted to avoid naming conflicts with other projects.
+   Replaced with nanosleep()
+
+ * Added simple tx/rx statistics command (ctrl-t s)
+
+   To display the total number of bytes transmitted/received simply perform the
+   'ctrl-t s' command sequence.
+
+   This feature can be useful when eg. trying to detect non-printable
+   characters.
+
+ * Further simplification of key handling
+
+   Changed so that the "ctrl-t ctrl-t" sequence is now simply "ctrl-t t" to
+   send the ctrl-t key code. This is inspired by screen which does similar
+   to send its command key code (ctrl-a a).
+
+   This change also allows to easier add new key commands if needed.
+
+   Updated man page accordingly.
+
+ * Cleaned up and simplified key handling
+
+Jakub Wilk:
+
+ * Insert output delay only if something was output
+
+
+
+Changes since tio v1.10:
+
+ * Enabled large file support (LFS)
+
+   Added autotools AC_SYS_LARGEFILE to support 64 bit file size handling.
+
+ * Updated tio title
+
+
+
+Changes since tio v1.9:
+
+ * Introduced lock on device file
+
+   Tio will now test for and obtain an advisory lock on the tty device file
+   to prevent starting multiple sessions on the same tty device.
+
+ * Updated AUTHORS
+
+Jakub Wilk:
+
+ * Treat EOF on stdin as error
+
+
+
+Changes since tio v1.8:
+
+ * Cleanup of error handling
+
+   Introduced consistent way of handling errors and printing error messages.
+
+   Also upgraded some warnings to errors.
+
+ * Updated localtime() error message
+
+ * Cleanup
+
+Jakub Wilk:
+
+ * Fix error handling for select()
+
+   Previously the error handling code for select() was unreachable.
+
+ * Removed unneeded quotes from AM_CFLAGS
+
+ * Expanded tabs
+
+ * Fixed setting "tainted"
+
+   Set "tainted" if and only if any character was read from the device.
+
+   Ctrl-t is no longer sent to the device on exit, so the trick to avoid
+   its echo is not necessary.
+
+   Characters read from stdin don't directly affect output, so they
+   shouldn't enable "tainted".
+
+ * Used \r in color_printf()
+
+   \033[300D is an unusual way to move the cursor back to column 1.
+   Use straightforward \r instead.
+
+ * Added missing \r\n to warning messages
+
+   \n alone is not enough, because the terminal is in raw mode.
+
+
+
+Changes since tio v1.7:
+
+ * Fixed enablement of compiler warnings
+
+ * Fixed log_open() prototype
+
+ * Fixed index error wrt ctrl-t detection
+
+ * Fixed handling of ctrl-t
+
+   Before, when exercising the quit key sequence (ctrl-t + q) the ctrl-t code
+   (0x14) would be sent.
+
+   This is now fixed so that it is not sent.
+
+   However, in case it is needed to send ctrl-t to the device it is possible by
+   simply repeating the ctrl-t.
+
+   Meaning, ctrl-t + ctrl-t = ctrl-t sent to device.
+
+ * Improved error handling
+
+   Fixes a memory leak and avoids aggressive busy looping when problems
+   accessing tty device.
+
+ * Removed redundant log_close() call
+
+ * Enabled compiler warnings
+
+Jakub Wilk:
+
+ * Stopped copying arguments to fixed-size buffers
+
+   Don't needlessly copy command-line arguments into fixed-size buffers.
+
+   Previously the program crashed if an overlong pathname was provided on
+   the command line. Also, some systems (such as GNU Hurd) don't define
+   MAXPATHLEN at all.
+
+ * Added const to log_open() prototype
+
+ * Completed the ^g to ^t transition
+
+   In 72a287f18995 the escape key was changed from ^g to ^t, but some
+   code and comments still referred to the old key.
+
+ * Used HTTPS for tio.github.io
+
+ * Man page beautification
+
+ * Bumped date in man page
+
+ * Improve man page formatting
+
+   Use regular font for metacharacters such as "[]", "," or "|";
+   use italic font for metavariables.
+
+ * Fixed hyphen vs minus vs em-dash confusion in man page
+
+   - prints as hyphen;
+   \- prints as minus sign;
+   \em prints as em-dash.
+
+
+
+Changes since tio v1.6:
+
+ * Changed escape key from ^g to ^t
+
+   After renaming to "tio" it makes sense to change the escape key
+   accordingly. Hence, the new escape key is ^t.
+
+   Meaning, in session, its now ctrl-t + q to quit.
+
+Jakub Wilk:
+
+ * Fixed silly "tio or tio" in man page
+
+ * Fixed typo
diff --git a/README b/README
index 8dbb1053f8c140eda84c70b3f99a27a0f13c657a..79e563a93e5d256755869e586d1fa043fb7b6f19 100644 (file)
--- a/README
+++ b/README
@@ -1,15 +1,16 @@
-=== tio - the simple TTY terminal I/O application ===
+=== tio - a simple TTY terminal I/O application ===
 
 
 1. Introduction
 
-    "tio" is a simple TTY terminal application which features a straightfoward
+    "tio" is a simple TTY terminal application which features a straightforward
     commandline interface to easily connect to TTY devices for basic
     input/output.
 
     It was created because the author needed a simple no-nonsense TTY
     terminal application to easily connect to various terminal TTY devices.
 
+
 2. Usage
 
     The commandline interface is straightforward as reflected in the output
           -v, --version               Display version
           -h, --help                  Display help
 
-        In session, press ctrl-g + q to quit.
+        In session, press ctrl-t + q to quit.
 
 
-    The only option which requires a bit of elaboration is the --no-autoconnect
-    option.
+    The only option which requires a bit of elaboration is perhaps the
+    --no-autoconnect option.
 
     By default tio automatically connects to the provided device if present.
     If the device is not present it will wait for it to appear and then
 
 3. Download
 
-    Find the latest release tarball at http://tio.github.io
+    Find the latest release tarball at https://tio.github.io
 
-    The latest source is available on github:
-    https://github.com/tio/tio
+    The latest source is available on github: https://github.com/tio/tio
 
 
 4. Installation
@@ -84,6 +84,6 @@
 
 8. Authors
 
-    Written by Martin Lund <martin.lund@keep-it-simple.com>
+    Created by Martin Lund <martin.lund@keep-it-simple.com>
 
-    See the AUTHORS file for full list of authors (including contributors).
+    See the AUTHORS file for full list of authors.
index 57506d402ec3374b9029bdd2a923f391afc75d22..4da23238c1218fb6d668c3028be217c607499521 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for tio 1.6.
+# Generated by GNU Autoconf 2.69 for tio 1.12.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -576,10 +576,10 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='tio'
 PACKAGE_TARNAME='tio'
-PACKAGE_VERSION='1.6'
-PACKAGE_STRING='tio 1.6'
+PACKAGE_VERSION='1.12'
+PACKAGE_STRING='tio 1.12'
 PACKAGE_BUGREPORT=''
-PACKAGE_URL='http://tio.github.io'
+PACKAGE_URL='https://tio.github.io'
 
 ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
@@ -681,6 +681,7 @@ ac_user_opts='
 enable_option_checking
 enable_silent_rules
 enable_dependency_tracking
+enable_largefile
 with_bash_completion_dir
 '
       ac_precious_vars='build_alias
@@ -1246,7 +1247,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures tio 1.6 to adapt to many kinds of systems.
+\`configure' configures tio 1.12 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1313,7 +1314,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of tio 1.6:";;
+     short | recursive ) echo "Configuration of tio 1.12:";;
    esac
   cat <<\_ACEOF
 
@@ -1327,6 +1328,7 @@ Optional Features:
                           do not reject slow dependency extractors
   --disable-dependency-tracking
                           speeds up one-time build
+  --disable-largefile     omit support for large files
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1357,7 +1359,7 @@ Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
 
 Report bugs to the package provider.
-tio home page: <http://tio.github.io>.
+tio home page: <https://tio.github.io>.
 _ACEOF
 ac_status=$?
 fi
@@ -1420,7 +1422,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tio configure 1.6
+tio configure 1.12
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1475,7 +1477,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by tio $as_me 1.6, which was
+It was created by tio $as_me 1.12, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2340,7 +2342,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='tio'
- VERSION='1.6'
+ VERSION='1.12'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3519,6 +3521,207 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+        # IRIX 6.2 and later do not support large files by default,
+        # so use the C compiler's -n32 option if that helps.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+        if ac_fn_c_try_compile "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext
+        CC="$CC -n32"
+        if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+        break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  fi
+
+
+fi
+
+
 
 
 
@@ -4273,7 +4476,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by tio $as_me 1.6, which was
+This file was extended by tio $as_me 1.12, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4334,13 +4537,13 @@ Configuration commands:
 $config_commands
 
 Report bugs to the package provider.
-tio home page: <http://tio.github.io>."
+tio home page: <https://tio.github.io>."
 
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-tio config.status 1.6
+tio config.status 1.12
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 0e58e0eb2c7bfe92bffc8fd2646a6a24048e6e83..4d403508c06c220c8dc8c104c65960069af854ed 100644 (file)
@@ -1,11 +1,12 @@
 AC_PREREQ([2.68])
-AC_INIT([tio], [1.6], [], [tio], [http://tio.github.io])
+AC_INIT([tio], [1.12], [], [tio], [https://tio.github.io])
 AC_CONFIG_HEADERS([src/include/config.h])
 AM_INIT_AUTOMAKE([1.11 foreign dist-xz no-dist-gzip -Wall -Werror])
 AM_SILENT_RULES([yes])
 AC_PROG_CC
 AC_LANG([C])
 AC_PROG_INSTALL
+AC_SYS_LARGEFILE
 
 PKG_PROG_PKG_CONFIG
 AC_ARG_WITH([bash-completion-dir],
index b25117341c433a5241026610c70f0dcbaf7d6bd9..953ecf5591d126e51d7aefa8bb0c92089ebb4d3f 100644 (file)
--- a/man/tio.1
+++ b/man/tio.1
@@ -1,67 +1,72 @@
-.TH "tio" "1" "30 September 2014"
+.TH "tio" "1" "7 May 2016"
 
 .SH "NAME"
-tio \- The simple TTY terminal I/O application
+tio \- a simple TTY terminal I/O application
 
 .SH "SYNOPSIS"
 .PP
 .B tio
-[<options>] <tty device>
+.RI "[" <options> "] " "<tty device>"
 
 .SH "DESCRIPTION"
 .PP
 .B tio
-or
-.B tio
 is a simple TTY terminal application which features a straightforward
 commandline interface to easily connect to TTY devices for basic input/output.
 
 .SH "OPTIONS"
 
 .TP
-.B \-b, \--baudrate <bps>
+.BR \-b ", " "\-\-baudrate " \fI<bps>
 
 Set baud rate [bps] (default: 115200).
 .TP
-.B \-d, \--databits 5|6|7|8
+.BR \-d ", " "\-\-databits 5" | 6 | 7 | 8
 
 Set data bits (default: 8).
 .TP
-.B \-f, \--flow hard|soft|none
+.BR \-f ", " "\-\-flow hard" | soft | none
 
 Set flow control (default: none).
 .TP
-.B \-s, \--stopbits 1|2
+.BR \-s ", " "\-\-stopbits 1" | 2
 
 Set stop bits (default: 1).
 .TP
-.B \-p, \--parity odd|even|none
+.BR \-p ", " "\-\-parity odd" | even | none
 
 Set parity (default: none).
 .TP
-.B \-o, \--output-delay <ms>
+.BR \-o ", " "\-\-output\-delay " \fI<ms>
 
-Set output delay [ms] - delay inserted between each transmitted character (default: 0).
+Set output delay [ms] \(em delay inserted between each transmitted character (default: 0).
 .TP
-.B \-n, \--no-autoconnect
+.BR \-n ", " \-\-no\-autoconnect
 
 Disable automatic connect.
 .TP
-.B \-l, \--log <filename>
+.BR \-l ", " "\-\-log " \fI<filename>
 
 Log to file.
 .TP
-.B \-v, \--version
+.BR \-v ", " \-\-version
 
 Display program version.
 .TP
-.B \-h, \--help
+.BR \-h ", " \-\-help
 
 Display help.
 
 .SH "KEYS"
-.TP
-In session, press ctrl-g + q to quit.
+.PP
+.TP 16n
+In session, the following key sequences are intercepted as tio commands:
+.IP "\fBctrl-t q"
+Quit
+.IP "\fBctrl-t s"
+Show session statistics (total number of bytes transmitted/received)
+.IP "\fBctrl-t t"
+Send ctrl-t key code
 
 .SH "EXAMPLES"
 .TP
@@ -71,15 +76,15 @@ tio /dev/ttyUSB0
 .TP
 Which corresponds to:
 
-tio -b 115200 -d 8 -f none -s 1 -p none /dev/ttyUSB0
+tio \-b 115200 \-d 8 \-f none \-s 1 \-p none /dev/ttyUSB0
 .TP
 It is recommended to connect serial tty devices by id. For example:
 
-tio /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
 .PP
 Using serial devices by id ensures that tio automatically reconnects to the
 correct serial device if the device is disconnected and then reconnected.
 
 .SH "AUTHOR"
 .PP
-Written by Martin Lund <martin.lund@keep-it-simple.com>.
+Written by Martin Lund <martin.lund@keep\-it\-simple.com>.
index 545a08cac8bc11582398dda612144a065abe8e2c..6129033b9e384345852c355fdd59cf29d9cf784a 100644 (file)
@@ -1,14 +1,17 @@
+AM_CFLAGS=-Wall
 bin_PROGRAMS = tio
 tio_SOURCES = tty.c \
-                options.c \
-                time.c \
-                main.c \
-                log.c \
-                include/tio/tty.h \
-                include/tio/options.h \
-                include/tio/time.h \
-                include/tio/print.h \
-                include/tio/log.h
+              options.c \
+              time.c \
+              main.c \
+              log.c \
+              error.c \
+              include/tio/tty.h \
+              include/tio/options.h \
+              include/tio/time.h \
+              include/tio/print.h \
+              include/tio/log.h \
+              include/tio/error.h
 
 if ENABLE_BASH_COMPLETION
 bashcompletiondir=@BASH_COMPLETION_DIR@
index 795d04e597f9403ed18b5eda16d85ebd6b3e3ef2..32328576d9664f3f45643434c99f6794b07af932 100644 (file)
@@ -103,7 +103,7 @@ am__installdirs = "$(DESTDIR)$(bindir)" \
        "$(DESTDIR)$(bashcompletiondir)"
 PROGRAMS = $(bin_PROGRAMS)
 am_tio_OBJECTS = tty.$(OBJEXT) options.$(OBJEXT) time.$(OBJEXT) \
-       main.$(OBJEXT) log.$(OBJEXT)
+       main.$(OBJEXT) log.$(OBJEXT) error.$(OBJEXT)
 tio_OBJECTS = $(am_tio_OBJECTS)
 tio_LDADD = $(LDADD)
 AM_V_P = $(am__v_P_@AM_V@)
@@ -282,16 +282,19 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
+AM_CFLAGS = -Wall
 tio_SOURCES = tty.c \
-                options.c \
-                time.c \
-                main.c \
-                log.c \
-                include/tio/tty.h \
-                include/tio/options.h \
-                include/tio/time.h \
-                include/tio/print.h \
-                include/tio/log.h
+              options.c \
+              time.c \
+              main.c \
+              log.c \
+              error.c \
+              include/tio/tty.h \
+              include/tio/options.h \
+              include/tio/time.h \
+              include/tio/print.h \
+              include/tio/log.h \
+              include/tio/error.h
 
 @ENABLE_BASH_COMPLETION_TRUE@bashcompletiondir = @BASH_COMPLETION_DIR@
 @ENABLE_BASH_COMPLETION_TRUE@dist_bashcompletion_DATA = bash-completion/tio
@@ -381,6 +384,7 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..ca5aa18
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * tio - a simple TTY terminal I/O application
+ *
+ * Copyright (c) 2014-2016  Martin Lund
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "tio/options.h"
+#include "tio/print.h"
+#include "tio/error.h"
+
+char error[1000];
+
+void error_exit(void)
+{
+    if ((error[0] != 0) && (option.no_autoconnect))
+        printf("\rError: %s\r\n", error);
+}
index d4b374f226396e3f7b75098c20c4163ef2b59896..e316f10482818d5201bb13de4318c4536a2268cb 100644 (file)
 
 /* Version number of package */
 #undef VERSION
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
diff --git a/src/include/tio/error.h b/src/include/tio/error.h
new file mode 100644 (file)
index 0000000..b770854
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * tio - a simple TTY terminal I/O application
+ *
+ * Copyright (c) 2014-2016  Martin Lund
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#define TIO_SUCCESS 0
+#define TIO_ERROR   1
+
+extern char error[1000];
+
+#define error_printf(format, args...) \
+   snprintf (error, 1000, format, ## args);
+
+void error_exit(void);
+
+#endif
index 82153a7a4f68a30d0f684bd85e3a0dccc5a16f55..a8e965674bc8a4413bf7f89660824e6f9e9e590a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -22,7 +22,7 @@
 #ifndef LOG_H
 #define LOG_H
 
-void log_open(char *filename);
+void log_open(const char *filename);
 void log_write(char c);
 void log_close(void);
 void log_exit(void);
index dc573527ed5481e357d447228b9b464a4297773a..09e65b30c252a884cb631f7108830d2c0e0f7000 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -30,9 +30,9 @@
 /* Options */
 struct option_t
 {
-    char tty_device[MAXPATHLEN];
+    const char *tty_device;
     bool log;
-    char log_filename[_POSIX_ARG_MAX];
+    const char *log_filename;
     bool no_autoconnect;
     int output_delay;
     struct termios tio;
index a5c2a904e9e3aac59e376b22e8758d49f9506e47..72541741918194affcd1aa27dc8ef26987ee2362 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
 #define ANSI_COLOR_RESET     "\x1b[0m"
 
 #define color_printf(format, args...) \
-   fprintf (stdout, "\033[300D" ANSI_COLOR_YELLOW format ANSI_COLOR_RESET "\033[300D\n", ## args); \
+   fprintf (stdout, "\r" ANSI_COLOR_YELLOW format ANSI_COLOR_RESET "\r\n", ## args); \
+   fflush(stdout);
+
+#define warning_printf(format, args...) \
+   fprintf (stdout, "\rWarning: " format "\r\n", ## args); \
    fflush(stdout);
 
 #ifdef DEBUG
index 8e0fef6785aa5dc31ee987fce7ab3e65ae6b05cd..fe155589b52adb8b4ffa520b25a357135f8af150 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -23,5 +23,6 @@
 #define TIME_H
 
 char * current_time(void);
+void delay(long ms);
 
 #endif
index 35060249fae0191b25a02b4a033e2782e3ab0613..cab663ecff26d007f5370b596f5ab822776f35af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
 #ifndef TTY_H
 #define TTY_H
 
-#define KEY_CTRL_G 0x07
 #define KEY_Q 0x71
+#define KEY_S 0x73
+#define KEY_T 0x74
+#define KEY_CTRL_T 0x14
 
 void configure_stdout(void);
 void restore_stdout(void);
index 157714a27975205fd9142b16b19cc09132ba48b8..f242606884771e6e15bf102ed24ebbbe0f80df28 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -29,7 +29,7 @@
 static FILE *fp;
 static bool error = false;
 
-void log_open(char *filename)
+void log_open(const char *filename)
 {
     fp = fopen(filename, "w+");
 
index 153eb4f312fa19af53cdd42b86e0a68bdef48d7f..d379f98ca6144c4dd8cac77294b5e670c413594f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "tio/options.h"
 #include "tio/tty.h"
 #include "tio/log.h"
+#include "tio/error.h"
+#include "tio/print.h"
 
 int main(int argc, char *argv[])
 {
     int status;
 
+    /* Install error exit handler */
+    atexit(&error_exit);
+
     /* Parse options */
     parse_options(argc, argv);
 
@@ -38,9 +44,6 @@ int main(int argc, char *argv[])
     /* Install log exit handler */
     atexit(&log_exit);
 
-    /* Restore output terminal on exit */
-    atexit(&restore_stdout);
-
     /* Create log file */
     if (option.log)
         log_open(option.log_filename);
@@ -58,8 +61,5 @@ int main(int argc, char *argv[])
         }
     }
 
-    /* Close log */
-    log_close();
-
     return status;
 }
index 7aab70fb69c378505fcc36eec20626afdb281dab..15b6f2a781272d947ab3d66f34e08f4d42fa9bff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -30,7 +30,7 @@
 #include <limits.h>
 #include "config.h"
 #include "tio/options.h"
-#include "tio/print.h"
+#include "tio/error.h"
 
 struct option_t option =
 {
@@ -57,7 +57,7 @@ void print_options_help(char *argv[])
     printf("  -v, --version               Display version\n");
     printf("  -h, --help                  Display help\n");
     printf("\n");
-    printf("In session, press ctrl-g + q to quit.\n");
+    printf("In session, press ctrl-t + q to quit.\n");
     printf("\n");
 }
 
@@ -71,7 +71,7 @@ void parse_options(int argc, char *argv[])
     if (argc == 1)
     {
         print_options_help(argv);
-        exit(0);
+        exit(EXIT_SUCCESS);
     }
 
     /* Set default termios settings:
@@ -94,7 +94,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'},
-            {"version",               no_argument,       0, 'v'},
+            {"version",        no_argument,       0, 'v'},
             {"help",           no_argument,       0, 'h'},
             {0,                0,                 0,  0 }
         };
@@ -213,7 +213,7 @@ void parse_options(int argc, char *argv[])
                         baudrate = B4000000;
                         break;
                     default:
-                        printf("Error: Invalid baud rate.\n");
+                        error_printf("Invalid baud rate");
                         exit(EXIT_FAILURE);
                 }
 
@@ -240,7 +240,7 @@ void parse_options(int argc, char *argv[])
                         option.tio.c_cflag |= CS8;
                         break;
                     default:
-                        printf("Error: Invalid data bits.\n");
+                        error_printf("Invalid data bits");
                         exit(EXIT_FAILURE);
                 }
                 break;
@@ -263,7 +263,7 @@ void parse_options(int argc, char *argv[])
                 }
                 else
                 {
-                    printf("Error: Invalid flow control.\n");
+                    error_printf("Invalid flow control");
                     exit(EXIT_FAILURE);
                 }
                 break;
@@ -279,7 +279,7 @@ void parse_options(int argc, char *argv[])
                         option.tio.c_cflag |= CSTOPB;
                         break;
                     default:
-                        printf("Error: Invalid stop bits.\n");
+                        error_printf("Invalid stop bits");
                         exit(EXIT_FAILURE);
                 }
                 break;
@@ -299,7 +299,7 @@ void parse_options(int argc, char *argv[])
                     option.tio.c_cflag &= ~PARENB;
                 else
                 {
-                    printf("Error: Invalid parity.\n");
+                    error_printf("Invalid parity");
                     exit(EXIT_FAILURE);
                 }
                 break;
@@ -314,7 +314,7 @@ void parse_options(int argc, char *argv[])
 
             case 'l':
                 option.log = true;
-                strncpy(option.log_filename, optarg, _POSIX_ARG_MAX);
+                option.log_filename = optarg;
                 break;
 
             case 'v':
@@ -324,38 +324,38 @@ void parse_options(int argc, char *argv[])
                 printf("License GPLv2: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>.\n");
                 printf("This is free software: you are free to change and redistribute it.\n");
                 printf("There is NO WARRANTY, to the extent permitted by law.\n");
-                exit(0);
+                exit(EXIT_SUCCESS);
                 break;
 
             case 'h':
                 print_options_help(argv);
-                exit(0);
+                exit(EXIT_SUCCESS);
                 break;
 
             case '?':
                 /* getopt_long already printed an error message */
-                exit(1);
+                exit(EXIT_FAILURE);
                 break;
 
             default:
-                exit(1);
+                exit(EXIT_FAILURE);
         }
     }
 
     /* Assume first non-option is the tty device name */
     if (optind < argc)
-        strcpy(option.tty_device, argv[optind++]);
+        option.tty_device = argv[optind++];
 
     if (strlen(option.tty_device) == 0)
     {
-        printf("Error: Missing device name.\n");
+        error_printf("Missing device name");
         exit(EXIT_FAILURE);
     }
 
     /* Print any remaining command line arguments (unknown options) */
     if (optind < argc)
     {
-        printf("%s: unknown arguments: ", argv[0]);
+        printf("Error: unknown arguments: ");
         while (optind < argc)
             printf("%s ", argv[optind++]);
         printf("\n");
index d86774f16b153f4f19e1cf1ca91a5e5194febe70..fd609b89cc403c4e66dcfb02a3eb0c7b9c182688 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -22,6 +22,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
+#include "tio/error.h"
+#include "tio/print.h"
 
 char * current_time(void)
 {
@@ -33,7 +35,7 @@ char * current_time(void)
     tmp = localtime(&t);
     if (tmp == NULL)
     {
-        perror("localtime");
+        error_printf("Retrieving local time failed");
         exit(EXIT_FAILURE);
     }
 
@@ -41,3 +43,13 @@ char * current_time(void)
 
     return time_string;
 }
+
+void delay(long ms)
+{
+    struct timespec ts;
+
+    ts.tv_sec = ms / 1000;
+    ts.tv_nsec = (ms % 1000) * 1000000;
+
+    nanosleep(&ts, NULL);
+}
index fd9d838bbf900b85a9c1ad50a7f04d49273233d7..6d318acefd00248ea4d787964cab4575adbb4b88 100644 (file)
--- a/src/tty.c
+++ b/src/tty.c
@@ -1,5 +1,5 @@
 /*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
  *
  * Copyright (c) 2014-2016  Martin Lund
  *
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
+#include <sys/file.h>
 #include <fcntl.h>
 #include <termios.h>
 #include <stdbool.h>
 #include "tio/options.h"
 #include "tio/time.h"
 #include "tio/log.h"
+#include "tio/error.h"
 
-static int connected = false;
-struct termios new_stdout, old_stdout, old_tio;
-static int fd;
+static struct termios new_stdout, old_stdout, old_tio;
+static long rx_total = 0, tx_total = 0;
+static bool connected = false;
 static bool tainted = false;
+static int fd;
+
+void handle_command_sequence(char input_char, char previous_char, char *output_char, bool *forward)
+{
+    char unused_char;
+    bool unused_bool;
+
+    /* Ignore unused arguments */
+    if (output_char == NULL)
+        output_char = &unused_char;
+
+    if (forward == NULL)
+        forward = &unused_bool;
+
+    /* Handle escape key commands */
+    if (previous_char == KEY_CTRL_T)
+    {
+        switch (input_char)
+        {
+            case KEY_Q:
+                /* Exit upon ctrl-t q sequence */
+                exit(EXIT_SUCCESS);
+            case KEY_T:
+                /* Send ctrl-t key code upon ctrl-t t sequence */
+                *output_char = KEY_CTRL_T;
+                break;
+            case KEY_S:
+                /* Show tx/rx statistics upon ctrl-t s sequence */
+                if (tainted)
+                    putchar('\n');
+                color_printf("[tio %s] Sent %ld bytes, received %ld bytes", current_time(), tx_total, rx_total);
+                tainted = false;
+                *forward = false;
+                break;
+            default:
+                /* Ignore unknown ctrl-t escaped keys */
+                *forward = false;
+                break;
+        }
+    }
+}
 
 void wait_for_tty_device(void)
 {
-    int ready, n;
-    struct stat status;
     fd_set rdfs;
+    int    status;
     struct timeval tv;
-    char c_stdin[3];
+    static char input_char, previous_char = 0;
+    static bool first = true;
 
     /* Loop until device pops up */
     while (true)
     {
-        /* Test for accessible device file */
-        if (access(option.tty_device, R_OK) == 0)
-            return;
-
-        /* Wait up to 1 second */
-        tv.tv_sec = 1;
-        tv.tv_usec = 0;
+        if (first)
+        {
+            /* Don't wait first time */
+            tv.tv_sec = 0;
+            tv.tv_usec = 1;
+            first = false;
+        } else
+        {
+            /* Wait up to 1 second */
+            tv.tv_sec = 1;
+            tv.tv_usec = 0;
+        }
 
         FD_ZERO(&rdfs);
         FD_SET(STDIN_FILENO, &rdfs);
 
         /* Block until input becomes available or timeout */
-        ready = select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv);
-        if (ready)
+        status = select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv);
+        if (status > 0)
         {
             /* Input from stdin ready */
 
             /* Read one character */
-            n = read(STDIN_FILENO, &c_stdin[0], 1);
+            status = read(STDIN_FILENO, &input_char, 1);
+            if (status <= 0)
+            {
+                error_printf("Could not read from stdin");
+                exit(EXIT_FAILURE);
+            }
 
-            /* Exit upon ctrl-g + q sequence */
-            c_stdin[2] = c_stdin[1];
-            c_stdin[1] = c_stdin[0];
-            if ((c_stdin[1] == KEY_Q) && (c_stdin[2] == KEY_CTRL_G))
-                exit(EXIT_SUCCESS);
+            /* Handle commands */
+            handle_command_sequence(input_char, previous_char, NULL, NULL);
+
+            previous_char = input_char;
+
+        } else if (status == -1)
+        {
+            error_printf("select() failed (%s)", strerror(errno));
+            exit(EXIT_FAILURE);
         }
+
+        /* Test for accessible device file */
+        if (access(option.tty_device, R_OK) == 0)
+            return;
     }
 }
 
@@ -87,7 +148,7 @@ void configure_stdout(void)
     /* Save current stdout settings */
     if (tcgetattr(STDOUT_FILENO, &old_stdout) < 0)
     {
-        printf("Error: Saving current stdio settings failed\n");
+        error_printf("Saving current stdio settings failed");
         exit(EXIT_FAILURE);
     }
 
@@ -107,11 +168,13 @@ void configure_stdout(void)
     /* Activate new stdout settings */
     tcsetattr(STDOUT_FILENO, TCSANOW, &new_stdout);
     tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new_stdout);
+
+    /* Make sure we restore old stdout settings on exit */
+    atexit(&restore_stdout);
 }
 
 void restore_stdout(void)
 {
-    tcflush(STDOUT_FILENO, TCIOFLUSH);
     tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdout);
     tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old_stdout);
 }
@@ -120,9 +183,14 @@ void disconnect_tty(void)
 {
     if (tainted)
         putchar('\n');
-    color_printf("[tio %s] Disconnected", current_time());
-    close(fd);
-    connected = false;
+
+    if (connected)
+    {
+        color_printf("[tio %s] Disconnected", current_time());
+        flock(fd, LOCK_UN);
+        close(fd);
+        connected = false;
+    }
 }
 
 void restore_tty(void)
@@ -138,19 +206,33 @@ int connect_tty(void)
 {
     fd_set rdfs;           /* Read file descriptor set */
     int    maxfd;          /* Maximum file descriptor used */
+    char   input_char, output_char;
+    static char previous_char = 0;
     static bool first = true;
     int    status;
-    char   c_tty;
-    char   c_stdin[3];
 
     /* Open tty device */
     fd = open(option.tty_device, O_RDWR | O_NOCTTY );
     if (fd < 0)
-        return EXIT_FAILURE;
+    {
+        error_printf("Could not open tty device (%s)", strerror(errno));
+        goto error_open;
+    }
 
     /* Make sure device is of tty type */
     if (!isatty(fd))
-        return EXIT_FAILURE;
+    {
+        error_printf("Not a tty device");
+        goto error_isatty;
+    }
+
+    /* Lock device file */
+    status = flock(fd, LOCK_EX | LOCK_NB);
+    if ((status == -1) && (errno == EWOULDBLOCK))
+    {
+        printf("Error: Device file is locked by another process\r\n");
+        exit(EXIT_FAILURE);
+    }
 
     /* Flush stale I/O data (if any) */
     tcflush(fd, TCIOFLUSH);
@@ -159,12 +241,10 @@ int connect_tty(void)
     color_printf("[tio %s] Connected", current_time());
     connected = true;
     tainted = false;
-    bzero(&c_stdin[0], 3);
-    c_tty = 0;
 
     /* Save current port settings */
     if (tcgetattr(fd, &old_tio) < 0)
-        return EXIT_FAILURE;
+        goto error_tcgetattr;
 
     /* Make sure we restore tty settings on exit */
     if (first)
@@ -196,54 +276,89 @@ int connect_tty(void)
         FD_SET(STDIN_FILENO, &rdfs);
 
         /* Block until input becomes available */
-        select(maxfd, &rdfs, NULL, NULL, NULL);
-        if (FD_ISSET(fd, &rdfs))
+        status = select(maxfd, &rdfs, NULL, NULL, NULL);
+        if (status > 0)
         {
-            /* Input from tty device ready */
-            if (read(fd, &c_tty, 1) > 0)
+            if (FD_ISSET(fd, &rdfs))
             {
-                /* Print received tty character to stdout */
-                putchar(c_tty);
-                fflush(stdout);
+                /* Input from tty device ready */
+                if (read(fd, &input_char, 1) > 0)
+                {
+                    /* Update receive statistics */
+                    rx_total++;
 
-                /* Write to log */
-                if (option.log)
-                    log_write(c_tty);
+                    /* Print received tty character to stdout */
+                    putchar(input_char);
+                    fflush(stdout);
+
+                    /* Write to log */
+                    if (option.log)
+                        log_write(input_char);
 
-                if (c_tty != 0x7) // Small trick to avoid ctrl-g echo
                     tainted = true;
-            } else
-            {
-                /* Error reading - device is likely unplugged */
-                disconnect_tty();
-                return EXIT_FAILURE;
+
+                } else
+                {
+                    /* Error reading - device is likely unplugged */
+                    error_printf("Could not read from tty device");
+                    goto error_read;
+                }
             }
-        }
-        if (FD_ISSET(STDIN_FILENO, &rdfs))
-        {
-            /* Input from stdin ready */
-            status = read(STDIN_FILENO, &c_stdin[0], 1);
-            if ((c_stdin[0] != KEY_Q) && (c_stdin[0] != KEY_CTRL_G))
-                tainted = true;
-
-            /* Exit upon ctrl-g + q sequence */
-            c_stdin[2] = c_stdin[1];
-            c_stdin[1] = c_stdin[0];
-            if ((c_stdin[1] == KEY_Q) && (c_stdin[2] == KEY_CTRL_G))
-                exit(EXIT_SUCCESS);
+            if (FD_ISSET(STDIN_FILENO, &rdfs))
+            {
+                bool forward = true;
+
+                /* Input from stdin ready */
+                status = read(STDIN_FILENO, &input_char, 1);
+                if (status <= 0)
+                {
+                    error_printf("Could not read from stdin");
+                    goto error_read;
+                }
+
+                /* Forward input to output except ctrl-t key */
+                output_char = input_char;
+                if (input_char == KEY_CTRL_T)
+                    forward = false;
 
-            /* Forward input to tty device */
-            status = write(fd, &c_stdin[0], 1);
+                /* Handle commands */
+                handle_command_sequence(input_char, previous_char, &output_char, &forward);
 
-            /* Write to log */
-            if (option.log)
-                log_write(c_stdin[0]);
+                if (forward)
+                {
+                    /* Send output to tty device */
+                    status = write(fd, &output_char, 1);
+                    if (status < 0)
+                        warning_printf("Could not write to tty device");
 
-            /* Insert output delay */
-            if (option.output_delay)
-                usleep(option.output_delay * 1000);
+                    /* Write to log */
+                    if (option.log)
+                        log_write(output_char);
+
+                    /* Update transmit statistics */
+                    tx_total++;
+
+                    /* Insert output delay */
+                    delay(option.output_delay);
+                }
+
+                /* Save previous key */
+                previous_char = input_char;
+
+            }
+        } else if (status == -1)
+        {
+            error_printf("Error: select() failed (%s)", strerror(errno));
+            exit(EXIT_FAILURE);
         }
     }
 
-    return EXIT_SUCCESS;
+    return TIO_SUCCESS;
+
+error_tcgetattr:
+error_isatty:
+error_read:
+    disconnect_tty();
+error_open:
+    return TIO_ERROR;
 }