From: git Date: Fri, 20 Feb 2026 19:14:53 +0000 (-0500) Subject: changes in define macros and switches, improved piping support X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=0722aca65eb4ee3fa9f6d072ae3bee1ea56775bd;p=ust.git changes in define macros and switches, improved piping support moved $TARGET to config.mk --- diff --git a/Makefile b/Makefile index 068f0fa..d30144b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ include config.mk -TARGET = ust SRC = ust.c OBJ = ${SRC:.c=.o} @@ -19,8 +18,8 @@ install: all cp -f ${TARGET} ${PREFIX}/bin chmod 755 ${PREFIX}/bin/${TARGET} mkdir -p ${MANPREFIX}/man1 - sed "s/VERSION/${VERSION}/" < ${TARGET}.1 > ${MANPREFIX}/man1/${TARGET}.1 - chmod 644 ${MANPREFIX}/man1/ust.1 + sed "s/VERSION/${VERSION}/" < ust.1 > ${MANPREFIX}/man1/${TARGET}.1 + chmod 644 ${MANPREFIX}/man1/${TARGET}.1 uninstall: rm -f ${PREFIX}/bin/${TARGET} ${MANPREFIX}/man1/${TARGET}.1 diff --git a/config.def.h b/config.def.h index 1e68dd1..ddb69f9 100644 --- a/config.def.h +++ b/config.def.h @@ -28,6 +28,10 @@ const char escapechar = '~'; /* print additional info to stderr */ int verbose = 0; /*(0|1)*/ +/* exit timeout after piped ust reaches EOF */ +long stimeout = 0; +long nstimeout = 1000; + /* * device name * diff --git a/config.mk b/config.mk index 5a1e325..36893ea 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,7 @@ VERSION = 0.2.1 +TARGET = ust + PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man diff --git a/ust.1 b/ust.1 index fd7c0e2..dd7c132 100644 --- a/ust.1 +++ b/ust.1 @@ -17,6 +17,8 @@ .Op Fl \-hardware\-dtr\-dsr|\-R .Op Fl \-software|\-X .Op Fl \-delay|\-d Ar # +.Op Fl \-timeout\-ns|\-f Ar # +.Op Fl \-timeout\-s|\-F Ar # .Op Fl \-min\-chars|\-m Ar # .Op Fl \-canonical|\-c .Op Fl \-echo|\-h @@ -43,9 +45,9 @@ This way the user might set a default config for a specific device without any a .Bl -tag -width ".Fl \-line|\-l Ar line" .It Fl \-line|\-l Ar line The device name can be input in two formats: -.Ar '/dev/cua00' +.Ar /dev/cua00 or -.Ar `cua00` . +.Ar cua00 . .It Fl \-speed|\-s Ar # | Ar \-# Baudrate set by this flag also applies to RX baud if that wasn't explicitly set. .It Fl \-rx\-speed|\-i Ar # @@ -74,6 +76,17 @@ Toggle DTR/DSR flow control (setting both hardware flow control options will ena Toggle XON/XOFF software flow control (can be enabled with hardware flow control simultaneously). .It Fl \-delay|\-d Ar # Delay between sending multiple characters (when redirecting stdin or writing a file) to the line in nanoseconds. +.It Fl \-timeout\-ns|\-f Ar # +With stdin redirected, +.Nm +will exit upon reaching +.Ar EOF , +this option sets a delay (in nanoseconds) after +.Ar EOF +encounter and before program exit. +.It Fl \-timeout\-s|\-F Ar # +.Ar EOF +exit delay (in seconds). .It Fl \-min\-chars|\-m Ar # The minimum of characters to input before they get sent to the line. .It Fl \-canonical|\-c @@ -112,7 +125,7 @@ Set new speed (both TX and RX). .It Ar d Set new character delay. .It Ar b -Toggle backspace character +Toggle the backspace key character .It Ar t No | Ar T Toggle a translation option (output|input). .It Ar c @@ -126,11 +139,11 @@ Send a DCD pulse. .Sh EXIT STATUS .Pp .Nm -exits 2 if some of the user\-set options were invalid and exits 1 on general errors. +exits 2 if some of the user\-set options were invalid (errors caused by trying to aply unsupported options to hardware, eg., setting unsupported baud, are considered as such) and exits 1 on general errors. .Sh EXAMPLES .Ed .Pp -Pipe the utility and write output to a file. +Pipe the utility and write output to a file: .Bd -literal -offset indent $ printf "00,78,FFFF\\r45\\r" | ust \-19200 \-d 9000000 > wozmon.out $ cat wozmon.out diff --git a/ust.c b/ust.c index 4517e0c..2aa9a24 100644 --- a/ust.c +++ b/ust.c @@ -26,10 +26,18 @@ #define DEL '\x7f' #define EOT '\x4' #define ESC '\x1b' + +#define IXONXOFF (IXON | IXOFF) + +#ifdef __linux__ + #define TERMIOS_STRUCT termios2 +#else + #define TERMIOS_STRUCT termios +#endif + #if defined(CCDTR_IFLOW) && defined(CDSR_OFLOW) #define CDTRDSR (CDTR_IFLOW | CDSR_OFLOW) #endif -#define IXONXOFF (IXON | IXOFF) typedef struct { char find; @@ -54,9 +62,9 @@ typedef struct{ /* including here to access CRLFOpt */ #include "config.h" -static int gettermattr(int dv, void *strct); -static int settermattr(int dv, const void *strct); -static void settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct); +static int gettermattr(int dv, struct TERMIOS_STRUCT *optst); +static int settermattr(int dv, const struct TERMIOS_STRUCT *optst); +static void settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst); static int openport(); static unsigned int strtoui(const char *str, const char *msg, unsigned int min); static int troptions(CRLFOpt *options, const char *str); @@ -74,62 +82,51 @@ static inline ssize_t rmchar(char *buff, ssize_t sread, int *scratch, const Args static void sighandl(int signo); static void die(int code, const char *msg, ...); -#ifdef __linux__ - static struct termios2 cntrl, origterm = { 0 }, newterm = { 0 }; -#else - static struct termios cntrl, origterm = { 0 }, newterm = { 0 }; -#endif +static struct TERMIOS_STRUCT cntrl, origterm = { 0 }, newterm = { 0 }; static Args bsargs = {DEL, DEL, 0}; -static Args nocrargs = {CR, 0, 0}; -static Args nolfargs = {LF, '\0', 0}; /* null-terminator is for use inside `getcmd()` */ -static Args lfincrargs = {CR, LF, 1}; -static Args crinlfargs = {LF, CR, -1}; -static const unsigned int uintmax = ~(unsigned int)0; /* unsigned -1 to return on error */ +static const Args nocrargs = {CR, 0, 0}, + nolfargs = {LF, '\0', 0}, /* null-terminator is for use inside `getcmd()` */ + lfincrargs = {CR, LF, 1}, + crinlfargs = {LF, CR, -1}; static struct timespec wts; +static const unsigned int uintmax = ~(unsigned int)0; /* unsigned -1 to return on error */ +static int interactive = 0; static char *writebuff = NULL; static char *readbuff = NULL; static int *scratchr = NULL; static int *scratchw = NULL; static int fd = -1; -static int interactive = 0; int -gettermattr(int dv, void *strct) +gettermattr(int dv, struct TERMIOS_STRUCT *optst) { #ifdef __linux__ - struct termios2 *optst = (struct termios2*)strct; return ioctl(dv, TCGETS2, optst); #else - struct termios *optst = (struct termios*)strct; return tcgetattr(dv, optst); #endif } int -settermattr(int dv, const void *strct) +settermattr(int dv, const struct TERMIOS_STRUCT *optst) { #ifdef __linux__ - struct termios2 *optst = (struct termios2*)strct; return ioctl(dv, TCSETS2, optst); #else - struct termios *optst = (struct termios*)strct; return tcsetattr(dv, TCSANOW, optst); #endif } void -settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct) +settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst) { #ifdef __linux__ - struct termios2 *optst = (struct termios2*)strct; - optst->c_cflag &= ~CBAUD; optst->c_cflag |= BOTHER; optst->c_ispeed = ispeed; optst->c_ospeed = ospeed; #else - struct termios *optst = (struct termios*)strct; cfsetispeed(optst, ispeed); cfsetospeed(optst, ospeed); #endif @@ -177,13 +174,18 @@ openport() die(1, "failed to lock the device, exiting now\n"); } } - + /* + * Baud + */ if (verbose) fprintf(stderr, "setting baudrate [RX:%u | TX:%u]\n", ispeed, ospeed); settermspd(ispeed, ospeed, &cntrl); if (settermattr(fd, &cntrl) == -1) die(2,"failed to set baudrate [RX:%u | TX:%u]\n", ispeed, ospeed); - + + /* + * Parity + */ cntrl.c_lflag = 0; cntrl.c_iflag &= ~(ISTRIP | BRKINT); cntrl.c_cflag &= ~(PARENB | PARODD); @@ -198,6 +200,10 @@ openport() if (settermattr(fd, &cntrl) == -1) die(2, "failed to set parity [even: %d, odd: %d]\n", parity & 1, (parity & 2) >> 1); + + /* + * Flow control + */ if (verbose) { /* it's so ugly and beautiful at the same time */ int t = (((hard & 1) << 1) & (hard & 2)) >> 1; @@ -230,12 +236,18 @@ openport() if (settermattr(fd, &cntrl) == -1) die(2, "failed to set flow control\n"); + /* + * CR and LF + */ cntrl.c_iflag &= ~(ICRNL | INLCR); cntrl.c_oflag &= ~(OCRNL | ONLRET | ONLCR); if (setroptions()) die(2, "failed to set cr-lf translation options\n"); + /* + * Data bits + */ if (verbose) fprintf(stderr, "setting data bits [%c]\n", datab); tcflag_t db = CS8; @@ -255,6 +267,9 @@ openport() if (settermattr(fd, &cntrl) == -1) die(2, "failed to set data bits [%c]\n", datab); + /* + * Stop bits + */ if (verbose) fprintf(stderr, "setting stop bits [%d]\n", stopb+1); if (stopb) @@ -267,7 +282,8 @@ openport() cntrl.c_cc[VMIN] = 1; cntrl.c_cc[VTIME] = 0; - + + /* flush both hardware buffers */ #ifdef __linux__ ioctl(fd, TCFLSH, TCIOFLUSH); #else @@ -292,7 +308,6 @@ strtoui(const char *str, const char *msg, unsigned int min) * but almost all compilers will just truncate the value so it's OK */ return (unsigned int)t; - /* termios's `speed_t` is a typedef for `unsigned int` */ } int @@ -357,15 +372,8 @@ lsbmask(unsigned int n) inline int termchck(const void *term) { - #ifdef __linux__ - struct termios2 *iterm = (struct termios2*)term; - #define TERMIOS_STRUCT termios2 - #else - struct termios *iterm = (struct termios*)term; - #define TERMIOS_STRUCT termios - #endif for (size_t i = 0; i < sizeof(struct TERMIOS_STRUCT); i++) - if (((char*)iterm)[i] != 0) + if (((char*)term)[i] != 0) return 1; return 0; @@ -375,8 +383,10 @@ void * writeport(void *unused) { Sizes msizes; - struct timespec ts; + struct timespec timeout, ts; + timeout.tv_sec = stimeout; + timeout.tv_nsec = nstimeout; ts.tv_sec = swritedelay; ts.tv_nsec = nswritedelay; wts.tv_sec = 0; @@ -425,9 +435,14 @@ writeport(void *unused) } else { write(fd, writebuff, 1); } + } else if (inln == 0 && !interactive) { + break; } nanosleep(&ts, NULL); } + /* ust kills itself upon receiving a signal so no fancy `nanosleep()` features needed */ + nanosleep(&timeout, NULL); + die(0, "\n[EOF]\n"); return NULL; } @@ -618,7 +633,6 @@ getcmd(int escape) case EOT: /* FALLTHROUGH */ case '.': die(0,"\n[EOT]\n"); - break; case 'b': if (backspace) bsargs.input = DEL; @@ -796,7 +810,7 @@ main(int argc, char **argv) if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') { asprintf(&t, "-s%s", argv[i] + 1); if (!t) { - fprintf(stderr, "cannot convert -# to -s#\n"); + fprintf(stderr, "%s: cannot convert -# to -s#\n", argv[0]); break; } argv[i] = t; @@ -817,6 +831,8 @@ main(int argc, char **argv) {"data", required_argument, NULL, 'D'}, {"delay", required_argument, NULL, 'd'}, {"min-chars", required_argument, NULL, 'm'}, + {"timeout-ns", required_argument, NULL, 'f'}, + {"timeout-s", required_argument, NULL, 'F'}, {"stop-bits", no_argument, NULL, 'S'}, {"backspace", no_argument, NULL, 'b'}, {"translation", required_argument, NULL, 't'}, @@ -828,7 +844,7 @@ main(int argc, char **argv) unsigned int tui; int oind, rxspdset, devset, c; oind = rxspdset = devset = 0; - while ((c = getopt_long(argc, argv, "bcd:D:ehi:l:m:oRrs:t:T:vX", longopt, &oind)) != -1) { + while ((c = getopt_long(argc, argv, "D:F:T:d:f:i:l:m:s:t:RXbcehorv", longopt, &oind)) != -1) { switch (c) { case 0: break; @@ -842,20 +858,26 @@ main(int argc, char **argv) hard ^= 2; break; case 'X': soft ^= 1; break; - case 'd':; + case 'd': /* FALLTHROUGH */ + case 'f': + case 'F':; char* endptr; long t; t = strtol(optarg, &endptr, 10); if (errno != 0 || *endptr != '\0' || t < 0) { - fprintf(stderr, "invalid character delay\n"); + fprintf(stderr, "%s: invalid character delay: %s\n", argv[0], optarg); goto ustusage; - } else { + } else if (c == 'd') { chardelay = t; + } else if (c == 'f'){ + nstimeout = t; + } else { + stimeout = t; } break; case 'D': if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) { - fprintf(stderr, "invalid number of data bits: %s\n", optarg); + fprintf(stderr, "%s: invalid number of data bits: %s\n", argv[0], optarg); goto ustusage; } else { datab = optarg[0]; @@ -884,11 +906,11 @@ main(int argc, char **argv) stopb ^= 1; break; case 'l': if (devset) { - fprintf(stderr, "cannot specify multiple devices\n"); + fprintf(stderr, "%s: cannot specify multiple devices\n", argv[0]); goto ustusage; } if (strlen(optarg) > 10) { - fprintf(stderr, "device name too long\n"); + fprintf(stderr, "%s: device name too long\n", argv[0]); goto ustusage; } if (strchr(optarg, '/')) { @@ -926,7 +948,8 @@ main(int argc, char **argv) " [--canonical|-c] [--echo|-h]\n" " [--translation|-t option]" " [--input-translation|-T option]\n" - " [--verbose|-v] [--backspace|-b]\n", + " [--verbose|-v] [--backspace|-b]" + " [--timeout-s|-F #] [--timeout-ns|-f #]", argv[0]); break; }