#include <sys/ioctl.h>
#include <errno.h>
-#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
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 int openport(void);
static unsigned int strtoui(const char *str, const char *msg, unsigned int min);
static int troptions(CRLFOpt *options, const char *str);
-static int setroptions();
+static int setroptions(void);
static inline unsigned int lsbmask(unsigned int n);
static inline int termchck(const struct TERMIOS_STRUCT *term);
-static void interchck();
-static void cechck();
-static void *writeport(void *unused);
-static void *readport(void *unused);
+static void interchck(void);
+static void cechck(void);
+static void *writeport(void *);
+static void *readport(void *);
static void getcmd(int escape);
static inline void replacechar(char *buff, ssize_t size, const Args *args);
static inline ssize_t addchar(char *buff, ssize_t size, int *scratch, const Sizes *msizes, const Args *args);
static int *scratchr = NULL;
static int *scratchw = NULL;
static int fd = -1;
+static long rwc = 0;
int
gettermattr(int dv, struct TERMIOS_STRUCT *optst)
}
int
-openport()
+openport(void)
{
int flags;
struct flock fl = { 0 };
if (gettermattr(fd, &cntrl) == -1)
die(1, "failed to get device attributes\n");
- fl.l_type = F_WRLCK;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0;
- fl.l_len = 0;
-
if (exclusive) {
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
die(1, "failed to lock the device, exiting now\n");
unsigned int
strtoui(const char *str, const char *msg, unsigned int min)
-{
+{
long t;
char *endptr;
}
int
-setroptions()
+setroptions(void)
{
- cntrl.c_iflag ^= (ICRNL & lsbmask(itropts.crtolf));
- cntrl.c_iflag ^= (INLCR & lsbmask(itropts.lftocr));
- cntrl.c_oflag ^= (OCRNL & lsbmask(tropts.crtolf));
+ cntrl.c_iflag ^= (ICRNL & lsbmask(itropts.crtolf));
+ cntrl.c_iflag ^= (INLCR & lsbmask(itropts.lftocr));
+ cntrl.c_oflag ^= (OCRNL & lsbmask(tropts.crtolf));
cntrl.c_oflag ^= (ONLRET & lsbmask(tropts.lftocr));
- cntrl.c_oflag ^= (ONLCR & lsbmask(tropts.crinlf));
+ cntrl.c_oflag ^= (ONLCR & lsbmask(tropts.crinlf));
return settermattr(fd, &cntrl);
}
}
void *
-writeport(void *unused)
+writeport(void *)
{
Sizes msizes;
- struct timespec timeout, ts;
+ struct timespec ts;
- timeout.tv_sec = stimeout;
- timeout.tv_nsec = nstimeout;
ts.tv_sec = swritedelay;
ts.tv_nsec = nswritedelay;
wts.tv_sec = 0;
if (inln > 1) {
for (int i = 0; i <= inln; i++) {
- write(fd, &writebuff[i], 1);
+ rwc -= write(fd, &writebuff[i], 1);
nanosleep(&wts, NULL);
}
} else {
- write(fd, writebuff, 1);
+ rwc -= 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, "[EOF]\n");
/* unreachable */
if (itropts.lfincr)
outln = addchar(readbuff, outln, scratchr, &msizes, &lfincrargs);
- write(STDOUT_FILENO, readbuff, outln);
+ rwc += write(STDOUT_FILENO, readbuff, outln);
}
nanosleep(&ts, NULL);
}
return NULL;
}
-inline void __attribute__((hot))
+inline void
replacechar(char *buff, ssize_t size, const Args *args)
{
for (int i = 0; i < size; i++)
buff[i] = args->input;
}
-inline ssize_t __attribute__((hot))
+inline ssize_t
addchar(char *buff, ssize_t size, int *scratch, const Sizes *sizes, const Args *args)
{
int to, c;
return (size + c);
}
-inline ssize_t __attribute__((hot))
+inline ssize_t
rmchar(char *buff, ssize_t size, int *scratch, const Args *args)
{
int c = 0;
case 'w':
cechck();
if (fgets(ttr, sizeof(ttr), stdin) != NULL) {
- replacechar(ttr, 63, &nolfargs);
ssize_t frln;
int wfd = open(ttr, O_RDONLY);
+ replacechar(ttr, 63, &nolfargs);
if (wfd == -1) {
perror("error opening file");
goto finish;
}
while ((frln = read(wfd, writebuff, wbuffsz - 1)) > 0) {
+ rwc += frln;
for (int i = 0; i <= frln; i++) {
if (tropts.nocr)
frln = rmchar(writebuff, frln, scratchw, &nocrargs);
if (tropts.lfincr)
frln = addchar(writebuff, frln, scratchw, &msizes, &lfincrargs);
- write(fd, &writebuff[i], 1);
+ rwc -= write(fd, &writebuff[i], 1);
nanosleep(&wts, NULL);
}
}
die(int code, const char *msg, ...)
{
va_list fpa;
+ while (rwc > 0) {
+ int t = rwc;
+ nanosleep(&wts, NULL);
+ if (t == rwc) break;
+ }
if (fd != -1)
close(fd);
}
int
-main(int argc, char **argv)
+main(int argc, char *argv[])
{
- char *t = NULL;
- /* glibc's `asprintf()` won't set the string to NULL on failure automatically */
+ long tl;
+ char *t;
+ char *endptr;
+ unsigned int tui;
+ int oind, rxspdset, devset, c;
+ oind = rxspdset = devset = 0;
+
for (int i = 1; i < argc; i++ ) {
if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') {
- asprintf(&t, "-s%s", argv[i] + 1);
- if (!t) {
+ if (asprintf(&t, "-s%s", argv[i] + 1) == -1) {
fprintf(stderr, "%s: cannot convert -# to -s#\n", argv[0]);
break;
}
{"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'},
{NULL, 0, NULL, 0}
};
- unsigned int tui;
- int oind, rxspdset, devset, c;
- oind = rxspdset = devset = 0;
- while ((c = getopt_long(argc, argv, "D:F:T:d:f:i:l:m:s:t:RXbcehorv", longopt, &oind)) != -1) {
+ while ((c = getopt_long(argc, argv, "D:T:d:i:l:m:s:t:RXbcehorv", longopt, &oind)) != -1) {
switch (c) {
case 0:
break;
hard ^= 2; break;
case 'X':
soft ^= 1; break;
- case 'd': /* FALLTHROUGH */
- case 'f':
- case 'F':;
- char* endptr;
- long t;
- t = strtol(optarg, &endptr, 10);
+ case 'd':
+ tl = strtol(optarg, &endptr, 10);
if (errno != 0 || *endptr != '\0' || t < 0) {
fprintf(stderr, "%s: invalid character delay: %s\n", argv[0], optarg);
goto ustusage;
- } else if (c == 'd') {
- chardelay = t;
- } else if (c == 'f'){
- nstimeout = t;
} else {
- stimeout = t;
+ chardelay = tl;
}
break;
case 'D':
- if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) {
+ if (optarg[1] != '\0' || !(optarg[0] >= '5' && optarg[0] <= '8')) {
fprintf(stderr, "%s: invalid number of data bits: %s\n", argv[0], optarg);
goto ustusage;
} else {
parity ^= 2; break;
case 'h':
half ^= 1; break;
- case 'i':
- tui = strtoui(optarg, "invalid rx speed: %s\n", 1);
- if (tui == uintmax)
- goto ustusage;
- ispeed = tui;
- rxspdset = 1;
- break;
+ case 'i': /* FALLTHROUGH */
case 's':
tui = strtoui(optarg, "invalid speed: %s\n", 1);
if (tui == uintmax)
goto ustusage;
- ospeed = tui;
+ if (c == 'i') {
+ ispeed = tui; rxspdset = 1;
+ } else {
+ ospeed = tui;
+ ispeed = rxspdset ? ispeed : ospeed;
+ }
break;
case 'S':
stopb ^= 1; break;