From: git Date: Tue, 17 Feb 2026 15:28:44 +0000 (-0500) Subject: Changed the way buffer processing functions take arguments X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=f63ad7e054d4566e45d5b6c16007fb0461a9ec7a;p=ust.git Changed the way buffer processing functions take arguments Formatting improvements --- diff --git a/config.def.h b/config.def.h index 8ccdb78..68e1a15 100644 --- a/config.def.h +++ b/config.def.h @@ -85,10 +85,10 @@ typedef struct{ int lftocr; int nocr; int nolf; -} crlfopt; +} CRLFOpt; -crlfopt tropts = {0}; -crlfopt itropts = {0}; +CRLFOpt tropts = {0}; +CRLFOpt itropts = {0}; /* * backspace: setting to one makes `^H` the backspace character, `^?` otherwise @@ -96,7 +96,7 @@ crlfopt itropts = {0}; int backspace = 0; /*(0|1)*/ int minchars = 1; -int chardelay = 0; +long chardelay = 0; /* * XON/XOFF flow control diff --git a/ust.c b/ust.c index 3fd1932..919d1d6 100644 --- a/ust.c +++ b/ust.c @@ -1,19 +1,19 @@ -#include -#include -#include -#include -#include +#include +#include #include #include -#include +#include +#include +#include +#include +#include #include -#include #include #ifdef __linux__ #include #include -#else +#else #include #endif @@ -29,24 +29,31 @@ #endif #define IXONXOFF (IXON | IXOFF) +typedef struct { + ssize_t sizem; + char find; + char input; + int offset; +} Args; + static int gettermattr(int dv, void *strct); -static int settermattr(int dv, void *strct); -static void settermspd(unsigned int lispeed, unsigned int lospeed, void *strct); +static int settermattr(int dv, const void *strct); +static void settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct); static int openport(); -static unsigned int strtoui(const char *str, const char *msg, const unsigned int min); -static int troptions(crlfopt *options, const char *str); +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 inline int termchck(const void *term); static void interchck(); static void cechck(); -static void sighandl(const int signo); -static void die(const int code, const char *msg, ...); static void *writeport(void *unused); static void *readport(void *unused); -static inline void replacechar(char *str, ssize_t size, const char find, const char repl); -static inline ssize_t addchar(char *str, int *scratch, ssize_t size, const size_t bsize, const char find, const char inp, const int offset); -static inline ssize_t rmchar(char *str, int *scratch, ssize_t size, const char find); static void getcmd(int escape); +static inline void replacechar(char *buff, ssize_t sread, const Args *args); +static inline ssize_t addchar(char *buff, ssize_t sread, int *scratch, const Args *args); +static inline ssize_t rmchar(char *buff, ssize_t sread, int *scratch, const Args *args); +static void sighandl(int signo); +static void die(int code, const char *msg, ...); #ifdef __linux__ static struct termios2 cntrl, origterm = {0}, newterm = {0}; @@ -64,171 +71,6 @@ static char backspc = DEL,tbackspc = DEL; static int fd = -1; static int interactive = 0; -int -main(int argc, char **argv) -{ - for (int i = 1; i < argc; i++ ) { - if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') { - char *t = NULL; - /* glibc's `asprintf()` won't set the string to NULL on failure automatically */ - asprintf(&t, "-s%s", argv[i] + 1); - if (!t) { - fprintf(stderr, "cannot convert -# to -s#\n"); - break; - } - argv[i] = t; - free(t); - } - } - - static struct option longopt[] = { - {"line", required_argument, NULL, 'l'}, - {"speed", required_argument, NULL, 's'}, - {"rx-speed", required_argument, NULL, 'i'}, - {"echo", no_argument, NULL, 'h'}, - {"canonical", no_argument, NULL, 'c'}, - {"odd", no_argument, NULL, 'o'}, - {"even", no_argument, NULL, 'e'}, - {"hardware-rts-cts", no_argument, NULL, 'R'}, - {"hardware-dtr-dsr", no_argument, NULL, 'r'}, - {"software", no_argument, NULL, 'X'}, - {"data", required_argument, NULL, 'D'}, - {"delay", required_argument, NULL, 'd'}, - {"min-chars", required_argument, NULL, 'm'}, - {"stop-bits", no_argument, NULL, 'S'}, - {"backspace", no_argument, NULL, 'b'}, - {"translation", required_argument, NULL, 't'}, - {"input-translation", required_argument, NULL, 'T'}, - {"verbose", no_argument, NULL, 'v'}, - {NULL, 0, NULL, 0} - }; - - unsigned int tui; - int oind = 0, rxspdset = 0, devset = 0, c; - while ((c = getopt_long(argc, argv, "bcd:D:ehi:l:m:oRrs:t:T:vX", longopt, &oind)) != -1) { - switch (c) { - case 0: - break; - case 'b': - backspace ^= 1; break; - case 'c': - canonical ^= 1; break; - case 'R': - hard ^= 1; break; - case 'r': - hard ^= 2; break; - case 'X': - soft ^= 1; break; - case 'd':; - char* endptr; - long t; - t = strtol(optarg, &endptr, 10); - if (errno != 0 || *endptr != '\0' || t < 0) { - fprintf(stderr, "invalid character delay\n"); - goto ustusage; - } else { - chardelay = t; - } - break; - case 'D': - if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) { - fprintf(stderr, "invalid number of data bits: %s\n", optarg); - goto ustusage; - } else { - datab = optarg[0]; - } - break; - case 'e': - parity ^= 1; break; - case 'o': - 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 's': - tui = strtoui(optarg, "invalid speed: %s\n", 1); - if (tui == uintmax) - goto ustusage; - ospeed = tui; - break; - case 'S': - stopb ^= 1; break; - case 'l': - if (devset) { - fprintf(stderr, "cannot specify multiple devices\n"); - goto ustusage; - } - if (strlen(optarg) > 10) { - fprintf(stderr, "device name too long\n"); - goto ustusage; - } - if (strchr(optarg, '/')) { - strcpy(line, optarg); - devset = 1; - } else { - sprintf(line, "/dev/%s", optarg); - devset = 1; - } - break; - case 'm': - tui = strtoui(optarg, "invalid number of characters: %s\n", 1); - if (tui == uintmax) - goto ustusage; - minchars = tui; - break; - case 't': - if (troptions(&tropts, optarg)) - goto ustusage; - break; - case 'T': - if (troptions(&itropts, optarg)) - goto ustusage; - break; - case 'v': - verbose ^= 1; break; - default: - ustusage: - die(2, "usage: %s [--line|-l line] [--speed|-s #|-#] [--rx-speed|-i #]\n" - " [--data-bits|-D #] [--stop-bits|-S]" - " [--even|-e] [--odd|-o]\n" - " [--hardware-rts-cts|-R]" - " [--hardware-dtr-dsr|-r] [--software|-X]\n" - " [--delay|-d #] [--min-chars|-m #]" - " [--canonical|-c] [--echo|-h]\n" - " [--translation|-t tropt]" - " [--input-translation|-T tropt]\n" - " [--verbose|-v] [--backspace|-b]\n", - argv[0]); - break; - } - - - } - - if (!rxspdset) - ispeed = ospeed; - - if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) - interactive = 1; - - signal(SIGHUP, sighandl); - signal(SIGINT, sighandl); - signal(SIGQUIT, sighandl); - signal(SIGTERM, sighandl); - - fd = openport(); - - pthread_t readthread, writethread; - pthread_create(&writethread, NULL, writeport, NULL); - pthread_create(&readthread, NULL, readport, NULL); -} - int gettermattr(int dv, void *strct) { @@ -242,7 +84,7 @@ gettermattr(int dv, void *strct) } int -settermattr(int dv, void *strct) +settermattr(int dv, const void *strct) { #ifdef __linux__ struct termios2 *optst = (struct termios2*)strct; @@ -254,7 +96,7 @@ settermattr(int dv, void *strct) } void -settermspd(unsigned int lispeed, unsigned int lospeed, void *strct) +settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct) { #ifdef __linux__ struct termios2 *optst = (struct termios2*)strct; @@ -389,7 +231,7 @@ openport() } unsigned int -strtoui(const char *str, const char *msg, const unsigned int min) +strtoui(const char *str, const char *msg, unsigned int min) { long t; char *endptr; @@ -408,7 +250,7 @@ strtoui(const char *str, const char *msg, const unsigned int min) } int -troptions(crlfopt *options, const char *str) +troptions(CRLFOpt *options, const char *str) { switch (str[0]) { case 'l': @@ -511,6 +353,18 @@ writeport(void *unused) int escape = 0; + + Args bsargs, nocrargs, nolfargs, lfincrargs; + bsargs.sizem = wbuffsz; + nocrargs = nolfargs = lfincrargs = bsargs; + + bsargs.find=backspc; bsargs.input=tbackspc; + + nocrargs.find = CR; + nolfargs.find = LF; + + lfincrargs.find = CR; lfincrargs.input = LF; lfincrargs.offset = 1; + for (;;) { ssize_t inln = read(STDIN_FILENO, writebuff, wbuffsz - 1); if (inln > 0) { @@ -526,14 +380,14 @@ writeport(void *unused) } if (backspc != tbackspc) - replacechar(writebuff, inln, backspc, tbackspc); + replacechar(writebuff, inln, &bsargs); if (tropts.nocr) - inln = rmchar(writebuff, scratchw, inln, CR); + inln = rmchar(writebuff, inln, scratchw, &nocrargs); if (tropts.nolf) - inln = rmchar(writebuff, scratchw, inln, LF); + inln = rmchar(writebuff, inln, scratchw, &nolfargs); if (tropts.lfincr) - inln = addchar(writebuff, scratchw, inln, wbuffsz, CR, LF, 1); + inln = addchar(writebuff, inln, scratchw, &lfincrargs); if (inln > 1) { for (int i = 0; i <= inln; i++) { @@ -565,6 +419,17 @@ readport(void *unused) interchck(); + Args nocrargs, nolfargs, crinlfargs, lfincrargs; + nocrargs.sizem = rbuffsz; + nolfargs = crinlfargs = lfincrargs = nocrargs; + + nocrargs.find = CR; + nolfargs.find = LF; + + lfincrargs.find = CR; lfincrargs.input = LF; lfincrargs.offset = 1; + crinlfargs.find = LF; crinlfargs.input = CR; crinlfargs.offset = -1; + + /* disable stdout buffering */ setvbuf(stdout, NULL, _IONBF, 0); @@ -572,13 +437,13 @@ readport(void *unused) ssize_t outln = read(fd, readbuff, rbuffsz - 1); if (outln > 0) { if (itropts.nocr) - outln = rmchar(readbuff, scratchw, outln, CR); + outln = rmchar(readbuff, outln, scratchr, &nocrargs); if (itropts.nolf) - outln = rmchar(readbuff, scratchw, outln, LF); + outln = rmchar(readbuff, outln, scratchr, &nolfargs); if (itropts.crinlf) - outln = addchar(readbuff, scratchw, outln, rbuffsz, LF, CR, -1); + outln = addchar(readbuff, outln, scratchr, &crinlfargs); if (itropts.lfincr) - outln = addchar(readbuff, scratchw, outln, rbuffsz, CR, LF, 1); + outln = addchar(readbuff, outln, scratchr, &lfincrargs); write(STDOUT_FILENO, readbuff, outln); } @@ -590,47 +455,50 @@ readport(void *unused) } inline void __attribute__((hot)) -replacechar(char *str, ssize_t size, const char find, const char repl) +replacechar(char *buff, ssize_t size, const Args *args) { for (int i = 0; i < size; i++) - if (str[i] == find) - str[i] = repl; + if (buff[i] == args->find) + buff[i] = args->input; } /* TODO: optimize the function and allow for offsets greater than 1 */ inline ssize_t __attribute__((hot)) -addchar(char *str, int *scratch, ssize_t size, const size_t bsize,const char find, const char inp, const int offset) +addchar(char *buff, ssize_t size, int *scratch, const Args *args) { int c = 0; + for (int i = 0; i < size; i++) { - if (str[i] == find) { + if (buff[i] == args->find) { scratch[c] = i; c++; } } if (!c) return(size); - if ((size + c) > bsize) - c = bsize - size; + if ((size + c) > args->sizem) + c = args->sizem - size; - if (scratch[0] == 0 && offset < 0) { - memmove(&str[0]+1, &str[0], size); + if (scratch[0] == 0 && args->offset < 0) { + memmove(&buff[0]+1, &buff[0], size); scratch[0] = 1; } for (int i = c; i > 0; i--) { - for (int s = size; s >= scratch[i]; s--) - str[s + offset] = str[s]; - str[scratch[i]] = inp; + int t = scratch[i]; + for (int s = size; s >= t;s--) + buff[s + args->offset] = buff[s]; + buff[t] = args->input; } return (size + c); } inline ssize_t __attribute__((hot)) -rmchar(char *str, int *scratch, ssize_t size, const char find) +rmchar(char *buff, ssize_t size, int *scratch, const Args *args) { int c = 0; + for (int i = 0; i < size; i++) { - if (str[i] == find) { + if (buff[i] == args->find) { scratch[c] = i; c++; } @@ -640,7 +508,7 @@ rmchar(char *str, int *scratch, ssize_t size, const char find) for (int i = c; i > 0; i--) for (int s = size; s >= scratch[i]; s--) - str[s] = str[s + 1]; + buff[s] = buff[s + 1]; return(size - c); } @@ -696,10 +564,13 @@ cechck() void getcmd(int escape) { + Args rmlf; char cmdchar; char ttr[64]; unsigned int tspd; + rmlf.find = LF; rmlf.input = '\0'; + if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) interactive = 1; @@ -711,148 +582,146 @@ getcmd(int escape) cmdchar = writebuff[1]; switch (cmdchar) { - case '.': - die(0,"\n[EOT]\n"); - break; - case 'b': - if (backspace) - tbackspc = DEL; - else - tbackspc = BS; - backspace = !backspace; - break; - case 'h': - if (half) - newterm.c_lflag &= ~ECHO; - else - newterm.c_lflag |= ECHO; - half = !half; - if (settermattr(STDOUT_FILENO, &newterm) < 0) - die(1, "failed to set terminal attributes\n"); - break; - case 'c': - if (canonical) - newterm.c_lflag &= ~ICANON; - else - newterm.c_lflag |= ICANON; - canonical = !canonical; - if (settermattr(STDOUT_FILENO, &newterm) < 0) - die(1, "failed to set terminal attributes\n"); - break; - case 'w': - cechck(); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, LF, '\0'); - ssize_t frln; - int wfd = open(ttr, O_RDONLY); - if (fd == -1) { - perror("error opening file"); - break; - } - - while ((frln = read(wfd, writebuff, wbuffsz - 1)) > 0) { - for (int i = 0; i <= frln; i++) { - write(fd, &writebuff[i], 1); - nanosleep(&wts, NULL); - } - } - } - goto finish; - case 's': - cechck(); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, LF, '\0'); - tspd = strtoui(ttr, "invalid speed\n", 0); - if (tspd != uintmax) { - ospeed = ispeed = tspd; - settermspd(ispeed, ospeed, &cntrl); - if (settermattr(fd, &cntrl) != 0) { - fprintf(stderr, "failed to set baudrate [RX:%u | TX:%u]\n", ispeed, ospeed); - } - } + case '.': + die(0,"\n[EOT]\n"); + break; + case 'b': + if (backspace) + tbackspc = DEL; + else + tbackspc = BS; + backspace = !backspace; + break; + case 'h': + if (half) + newterm.c_lflag &= ~ECHO; + else + newterm.c_lflag |= ECHO; + half = !half; + if (settermattr(STDOUT_FILENO, &newterm) < 0) + die(1, "failed to set terminal attributes\n"); + break; + case 'c': + if (canonical) + newterm.c_lflag &= ~ICANON; + else + newterm.c_lflag |= ICANON; + canonical = !canonical; + if (settermattr(STDOUT_FILENO, &newterm) < 0) + die(1, "failed to set terminal attributes\n"); + break; + case 'w': + cechck(); + if (fgets(ttr, sizeof(ttr), stdin) != NULL) { + replacechar(ttr, 63, &rmlf); + ssize_t frln; + int wfd = open(ttr, O_RDONLY); + if (fd == -1) { + perror("error opening file"); + break; } - goto finish; - case 'd': - cechck(); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, LF, '\0'); - chardelay = strtoui(ttr, "invalid delay\n", 0); - if (chardelay != uintmax) { - wts.tv_sec = 0; - wts.tv_nsec = chardelay; + while ((frln = read(wfd, writebuff, wbuffsz - 1)) > 0) { + for (int i = 0; i <= frln; i++) { + write(fd, &writebuff[i], 1); + nanosleep(&wts, NULL); } } - goto finish; - case 't': - cechck(); - fprintf(stderr, "additional output translation option: "); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, LF, '\0'); - if(troptions(&tropts, ttr)) - goto finish; - if (setroptions()) - fprintf(stderr, "could not set new options\n"); - - } - goto finish; - case 'T': - cechck(); - printf("additional input translation option: "); - if (fgets(ttr, sizeof(ttr), stdin) != NULL) { - replacechar(ttr, 63, LF, '\0'); - if (troptions(&itropts, ttr)) - goto finish; - if (setroptions()) - fprintf(stderr, "could not set new options\n"); - } - finish: - if (!half && interactive) - newterm.c_lflag &= ~ECHO; - if (!canonical && interactive) - newterm.c_lflag &= ~ICANON; - settermattr(STDIN_FILENO, &newterm); - break; - case 'p':; - int st; - struct timespec ts; - ts.tv_sec = spulsedelay; - ts.tv_nsec = nspulsedelay; - - if (ioctl(fd, TIOCMGET, &st) != 0) { - fprintf(stderr, "failed to get port status\n"); - break; + } + goto finish; + case 's': + cechck(); + if (fgets(ttr, sizeof(ttr), stdin) != NULL) { + replacechar(ttr, 63, &rmlf); + tspd = strtoui(ttr, "invalid speed\n", 0); + if (tspd != uintmax) { + ospeed = ispeed = tspd; + settermspd(ispeed, ospeed, &cntrl); + if (settermattr(fd, &cntrl) != 0) + fprintf(stderr, "failed to set baudrate " + "[RX:%u | TX:%u]\n", ispeed, ospeed); } - st ^= TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &st) != 0) { - fprintf(stderr, "failed to set DTR [assertion]\n"); - break; + } + goto finish; + case 'd': + cechck(); + if (fgets(ttr, sizeof(ttr), stdin) != NULL) { + replacechar(ttr, 63, &rmlf); + chardelay = strtoui(ttr, "invalid delay\n", 0); + if (chardelay != uintmax) { + wts.tv_sec = 0; + wts.tv_nsec = chardelay; } - - nanosleep(&ts, NULL); - - st ^= TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &st) != 0) - fprintf(stderr, "failed to set DTR [negation]\n"); - break; - case BS: - case DEL: - case ESC: + } + goto finish; + case 't': + cechck(); + fprintf(stderr, "additional output translation option: "); + if (fgets(ttr, sizeof(ttr), stdin) != NULL) { + replacechar(ttr, 63, &rmlf); + if(troptions(&tropts, ttr)) + goto finish; + if (setroptions()) + fprintf(stderr, "could not set new options\n"); + } + goto finish; + case 'T': + cechck(); + printf("additional input translation option: "); + if (fgets(ttr, sizeof(ttr), stdin) != NULL) { + replacechar(ttr, 63, &rmlf); + if (troptions(&itropts, ttr)) + goto finish; + if (setroptions()) + fprintf(stderr, "could not set new options\n"); + } + finish: + if (!half && interactive) + newterm.c_lflag &= ~ECHO; + if (!canonical && interactive) + newterm.c_lflag &= ~ICANON; + if (settermattr(STDIN_FILENO, &newterm) == -1) + fprintf(stderr, "failed to restore echo and/or canonical mode\n"); + break; + case 'p':; + int st; + struct timespec ts; + ts.tv_sec = spulsedelay; + ts.tv_nsec = nspulsedelay; + + if (ioctl(fd, TIOCMGET, &st) != 0) { + fprintf(stderr, "failed to get port status\n"); break; - default: - fprintf(stderr, "not a valid command [%c]\n", cmdchar); + } + st ^= TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &st) != 0) { + fprintf(stderr, "failed to set DTR [assertion]\n"); break; + } + nanosleep(&ts, NULL); + + st ^= TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &st) != 0) + fprintf(stderr, "failed to set DTR [negation]\n"); + break; + case BS: /* FALLTHROUGH */ + case DEL: + case ESC: + break; + default: + fprintf(stderr, "not a valid command [%c]\n", cmdchar); + break; } return; } void -sighandl(const int signo) +sighandl(int signo) { die(128 + signo, "\nrecieved signal [%d], exiting\n", signo); } void -die(const int code, const char *msg, ...) +die(int code, const char *msg, ...) { va_list fpa; if (fd != -1) @@ -876,3 +745,169 @@ die(const int code, const char *msg, ...) exit(code); } + +int +main(int argc, char **argv) +{ + for (int i = 1; i < argc; i++ ) { + if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') { + char *t = NULL; + /* glibc's `asprintf()` won't set the string to NULL on failure automatically */ + asprintf(&t, "-s%s", argv[i] + 1); + if (!t) { + fprintf(stderr, "cannot convert -# to -s#\n"); + break; + } + argv[i] = t; + free(t); + } + } + + static struct option longopt[] = { + {"line", required_argument, NULL, 'l'}, + {"speed", required_argument, NULL, 's'}, + {"rx-speed", required_argument, NULL, 'i'}, + {"echo", no_argument, NULL, 'h'}, + {"canonical", no_argument, NULL, 'c'}, + {"odd", no_argument, NULL, 'o'}, + {"even", no_argument, NULL, 'e'}, + {"hardware-rts-cts", no_argument, NULL, 'R'}, + {"hardware-dtr-dsr", no_argument, NULL, 'r'}, + {"software", no_argument, NULL, 'X'}, + {"data", required_argument, NULL, 'D'}, + {"delay", required_argument, NULL, 'd'}, + {"min-chars", required_argument, NULL, 'm'}, + {"stop-bits", no_argument, NULL, 'S'}, + {"backspace", no_argument, NULL, 'b'}, + {"translation", required_argument, NULL, 't'}, + {"input-translation", required_argument, NULL, 'T'}, + {"verbose", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + 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) { + switch (c) { + case 0: + break; + case 'b': + backspace ^= 1; break; + case 'c': + canonical ^= 1; break; + case 'R': + hard ^= 1; break; + case 'r': + hard ^= 2; break; + case 'X': + soft ^= 1; break; + case 'd':; + char* endptr; + long t; + t = strtol(optarg, &endptr, 10); + if (errno != 0 || *endptr != '\0' || t < 0) { + fprintf(stderr, "invalid character delay\n"); + goto ustusage; + } else { + chardelay = t; + } + break; + case 'D': + if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) { + fprintf(stderr, "invalid number of data bits: %s\n", optarg); + goto ustusage; + } else { + datab = optarg[0]; + } + break; + case 'e': + parity ^= 1; break; + case 'o': + 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 's': + tui = strtoui(optarg, "invalid speed: %s\n", 1); + if (tui == uintmax) + goto ustusage; + ospeed = tui; + break; + case 'S': + stopb ^= 1; break; + case 'l': + if (devset) { + fprintf(stderr, "cannot specify multiple devices\n"); + goto ustusage; + } + if (strlen(optarg) > 10) { + fprintf(stderr, "device name too long\n"); + goto ustusage; + } + if (strchr(optarg, '/')) { + strcpy(line, optarg); + devset = 1; + } else { + sprintf(line, "/dev/%s", optarg); + devset = 1; + } + break; + case 'm': + tui = strtoui(optarg, "invalid number of characters: %s\n", 1); + if (tui == uintmax) + goto ustusage; + minchars = tui; + break; + case 't': + if (troptions(&tropts, optarg)) + goto ustusage; + break; + case 'T': + if (troptions(&itropts, optarg)) + goto ustusage; + break; + case 'v': + verbose ^= 1; break; + default: + ustusage: + die(2, "usage: %s [--line|-l line] [--speed|-s #|-#] [--rx-speed|-i #]\n" + " [--data-bits|-D #] [--stop-bits|-S]" + " [--even|-e] [--odd|-o]\n" + " [--hardware-rts-cts|-R]" + " [--hardware-dtr-dsr|-r] [--software|-X]\n" + " [--delay|-d #] [--min-chars|-m #]" + " [--canonical|-c] [--echo|-h]\n" + " [--translation|-t tropt]" + " [--input-translation|-T tropt]\n" + " [--verbose|-v] [--backspace|-b]\n", + argv[0]); + break; + } + + + } + + if (!rxspdset) + ispeed = ospeed; + + if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) + interactive = 1; + + signal(SIGHUP, sighandl); + signal(SIGINT, sighandl); + signal(SIGQUIT, sighandl); + signal(SIGTERM, sighandl); + + fd = openport(); + + pthread_t readthread, writethread; + pthread_create(&writethread, NULL, writeport, NULL); + pthread_create(&readthread, NULL, readport, NULL); +}