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.
-=== 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
-=== 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
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.
#! /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.
# 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
enable_option_checking
enable_silent_rules
enable_dependency_tracking
+enable_largefile
with_bash_completion_dir
'
ac_precious_vars='build_alias
# 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]...
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
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]
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
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.
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 $@
# Define the identity of the package.
PACKAGE='tio'
- VERSION='1.6'
+ VERSION='1.12'
cat >>confdefs.h <<_ACEOF
+# 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
+
+
# 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
$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\\"
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],
-.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
.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>.
+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@
"$(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@)
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
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@
--- /dev/null
+/*
+ * 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);
+}
/* 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
--- /dev/null
+/*
+ * 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
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
#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);
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
/* 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;
/*
- * 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
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
#define TIME_H
char * current_time(void);
+void delay(long ms);
#endif
/*
- * 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);
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
static FILE *fp;
static bool error = false;
-void log_open(char *filename)
+void log_open(const char *filename)
{
fp = fopen(filename, "w+");
/*
- * 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);
/* 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);
}
}
- /* Close log */
- log_close();
-
return status;
}
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
#include <limits.h>
#include "config.h"
#include "tio/options.h"
-#include "tio/print.h"
+#include "tio/error.h"
struct option_t option =
{
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");
}
if (argc == 1)
{
print_options_help(argv);
- exit(0);
+ exit(EXIT_SUCCESS);
}
/* Set default termios settings:
{"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 }
};
baudrate = B4000000;
break;
default:
- printf("Error: Invalid baud rate.\n");
+ error_printf("Invalid baud rate");
exit(EXIT_FAILURE);
}
option.tio.c_cflag |= CS8;
break;
default:
- printf("Error: Invalid data bits.\n");
+ error_printf("Invalid data bits");
exit(EXIT_FAILURE);
}
break;
}
else
{
- printf("Error: Invalid flow control.\n");
+ error_printf("Invalid flow control");
exit(EXIT_FAILURE);
}
break;
option.tio.c_cflag |= CSTOPB;
break;
default:
- printf("Error: Invalid stop bits.\n");
+ error_printf("Invalid stop bits");
exit(EXIT_FAILURE);
}
break;
option.tio.c_cflag &= ~PARENB;
else
{
- printf("Error: Invalid parity.\n");
+ error_printf("Invalid parity");
exit(EXIT_FAILURE);
}
break;
case 'l':
option.log = true;
- strncpy(option.log_filename, optarg, _POSIX_ARG_MAX);
+ option.log_filename = optarg;
break;
case 'v':
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");
/*
- * 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 <time.h>
+#include "tio/error.h"
+#include "tio/print.h"
char * current_time(void)
{
tmp = localtime(&t);
if (tmp == NULL)
{
- perror("localtime");
+ error_printf("Retrieving local time failed");
exit(EXIT_FAILURE);
}
return time_string;
}
+
+void delay(long ms)
+{
+ struct timespec ts;
+
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+
+ nanosleep(&ts, NULL);
+}
/*
- * tio - the simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
#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;
}
}
/* 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);
}
/* 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);
}
{
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)
{
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);
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)
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;
}