mirror of
https://github.com/UzixLS/picocom.git
synced 2025-07-19 07:21:18 +03:00
Added features:
- Local echo - Configurable input mapping (CR --> LF, DEL --> BS, etc) - Configurable output mapping - Configurable local-echo mapping May still need some testing...
This commit is contained in:
225
picocom.c
225
picocom.c
@ -54,6 +54,7 @@
|
||||
#define KEY_FLOW '\x06' /* C-f: change flowcntrl mode */
|
||||
#define KEY_PARITY '\x19' /* C-y: change parity mode */
|
||||
#define KEY_BITS '\x02' /* C-b: change number of databits */
|
||||
#define KEY_LECHO '\x03' /* C-c: toggle local echo */
|
||||
#define KEY_STATUS '\x16' /* C-v: show program option */
|
||||
#define KEY_SEND '\x13' /* C-s: send file */
|
||||
#define KEY_RECEIVE '\x12' /* C-r: receive file */
|
||||
@ -64,6 +65,74 @@
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* implemented caracter mappings */
|
||||
#define M_CRLF (1 << 0) /* map CR --> LF */
|
||||
#define M_CRCRLF (1 << 1) /* map CR --> CR + LF */
|
||||
#define M_IGNCR (1 << 2) /* map CR --> <nothing> */
|
||||
#define M_LFCR (1 << 3) /* map LF --> CR */
|
||||
#define M_LFCRLF (1 << 4) /* map LF --> CR + LF */
|
||||
#define M_IGNLF (1 << 5) /* map LF --> <nothing> */
|
||||
#define M_DELBS (1 << 6) /* map DEL --> BS */
|
||||
#define M_BSDEL (1 << 7) /* map BS --> DEL */
|
||||
#define M_NFLAGS 8
|
||||
|
||||
/* default character mappings */
|
||||
#define M_I_DFL 0
|
||||
#define M_O_DFL 0
|
||||
#define M_E_DFL (M_DELBS | M_CRCRLF)
|
||||
|
||||
/* character mapping names */
|
||||
struct map_names_s {
|
||||
char *name;
|
||||
int flag;
|
||||
} map_names[] = {
|
||||
{ "crlf", M_CRLF },
|
||||
{ "crcrlf", M_CRCRLF },
|
||||
{ "igncr", M_IGNCR },
|
||||
{ "lfcr", M_LFCR },
|
||||
{ "lfcrlf", M_LFCRLF },
|
||||
{ "ignlf", M_IGNLF },
|
||||
{ "delbs", M_DELBS },
|
||||
{ "bsdel", M_BSDEL },
|
||||
/* Sentinel */
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
int
|
||||
parse_map (char *s)
|
||||
{
|
||||
char *m, *t;
|
||||
int f, flags, i;
|
||||
|
||||
flags = 0;
|
||||
while ( (t = strtok(s, ", \t")) ) {
|
||||
for (i=0; (m = map_names[i].name); i++) {
|
||||
if ( ! strcmp(t, m) ) {
|
||||
f = map_names[i].flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( m ) flags |= f;
|
||||
else { flags = -1; break; }
|
||||
s = NULL;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
print_map (int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < M_NFLAGS; i++)
|
||||
if ( flags & (1 << i) )
|
||||
printf("%s,", map_names[i].name);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
struct {
|
||||
char port[128];
|
||||
int baud;
|
||||
@ -72,6 +141,7 @@ struct {
|
||||
enum parity_e parity;
|
||||
char *parity_str;
|
||||
int databits;
|
||||
int lecho;
|
||||
int noinit;
|
||||
int noreset;
|
||||
#ifdef UUCP_LOCK_DIR
|
||||
@ -80,6 +150,9 @@ struct {
|
||||
unsigned char escape;
|
||||
char send_cmd[128];
|
||||
char receive_cmd[128];
|
||||
int imap;
|
||||
int omap;
|
||||
int emap;
|
||||
} opts = {
|
||||
.port = "",
|
||||
.baud = 9600,
|
||||
@ -88,6 +161,7 @@ struct {
|
||||
.parity = P_NONE,
|
||||
.parity_str = "none",
|
||||
.databits = 8,
|
||||
.lecho = 0,
|
||||
.noinit = 0,
|
||||
.noreset = 0,
|
||||
#ifdef UUCP_LOCK_DIR
|
||||
@ -95,7 +169,10 @@ struct {
|
||||
#endif
|
||||
.escape = '\x01',
|
||||
.send_cmd = "sz -vv",
|
||||
.receive_cmd = "rz -vv"
|
||||
.receive_cmd = "rz -vv",
|
||||
.imap = M_I_DFL,
|
||||
.omap = M_O_DFL,
|
||||
.emap = M_E_DFL
|
||||
};
|
||||
|
||||
int tty_fd;
|
||||
@ -293,6 +370,76 @@ out:
|
||||
|
||||
#undef cput
|
||||
|
||||
/* maximum number of chars that can replace a single characted
|
||||
due to mapping */
|
||||
#define M_MAXMAP 4
|
||||
|
||||
int
|
||||
do_map (char *b, int map, char c)
|
||||
{
|
||||
int n;
|
||||
|
||||
switch (c) {
|
||||
case '\x7f':
|
||||
/* DEL mapings */
|
||||
if ( map & M_DELBS ) {
|
||||
b[0] = '\x08'; n = 1;
|
||||
} else {
|
||||
b[0] = c; n = 1;
|
||||
}
|
||||
break;
|
||||
case '\x08':
|
||||
/* BS mapings */
|
||||
if ( map & M_BSDEL ) {
|
||||
b[0] = '\x7f'; n = 1;
|
||||
} else {
|
||||
b[0] = c; n = 1;
|
||||
}
|
||||
break;
|
||||
case '\x0d':
|
||||
/* CR mappings */
|
||||
if ( map & M_CRLF ) {
|
||||
b[0] = '\x0a'; n = 1;
|
||||
} else if ( map & M_CRCRLF ) {
|
||||
b[0] = '\x0d'; b[1] = '\x0a'; n = 2;
|
||||
} else if ( map & M_IGNCR ) {
|
||||
n = 0;
|
||||
} else {
|
||||
b[0] = c; n = 1;
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
/* LF mappings */
|
||||
if ( map & M_LFCR ) {
|
||||
b[0] = '\x0d'; n = 1;
|
||||
} else if ( map & M_LFCRLF ) {
|
||||
b[0] = '\x0d'; b[1] = '\x0a'; n = 2;
|
||||
} else if ( map & M_IGNLF ) {
|
||||
n = 0;
|
||||
} else {
|
||||
b[0] = c; n = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
b[0] = c; n = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
map_and_write (int fd, int map, char c)
|
||||
{
|
||||
char b[M_MAXMAP];
|
||||
int n;
|
||||
|
||||
n = do_map(b, map, c);
|
||||
if ( n )
|
||||
if ( writen_ni(fd, b, n) < n )
|
||||
fatal("write to stdout failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
int
|
||||
@ -558,9 +705,13 @@ loop(void)
|
||||
if ( c == opts.escape ) {
|
||||
state = ST_TRANSPARENT;
|
||||
/* pass the escape character down */
|
||||
if (tty_q.len <= TTY_Q_SZ)
|
||||
tty_q.buff[tty_q.len++] = c;
|
||||
else
|
||||
if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) {
|
||||
n = do_map((char *)tty_q.buff + tty_q.len,
|
||||
opts.omap, c);
|
||||
tty_q.len += n;
|
||||
if ( opts.lecho )
|
||||
map_and_write(STO, opts.emap, c);
|
||||
} else
|
||||
fd_printf(STO, "\x07");
|
||||
break;
|
||||
}
|
||||
@ -639,6 +790,11 @@ loop(void)
|
||||
fd_printf(STO, "\r\n*** databits: %d ***\r\n",
|
||||
opts.databits);
|
||||
break;
|
||||
case KEY_LECHO:
|
||||
opts.lecho = ! opts.lecho;
|
||||
fd_printf(STO, "\r\n*** local echo: %s ***\r\n",
|
||||
opts.lecho ? "yes" : "no");
|
||||
break;
|
||||
case KEY_SEND:
|
||||
fd_printf(STO, "\r\n*** file: ");
|
||||
r = fd_readline(STI, STO, fname, sizeof(fname));
|
||||
@ -673,9 +829,13 @@ loop(void)
|
||||
if ( c == opts.escape ) {
|
||||
state = ST_COMMAND;
|
||||
} else {
|
||||
if (tty_q.len <= TTY_Q_SZ)
|
||||
tty_q.buff[tty_q.len++] = c;
|
||||
else
|
||||
if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) {
|
||||
n = do_map((char *)tty_q.buff + tty_q.len,
|
||||
opts.omap, c);
|
||||
tty_q.len += n;
|
||||
if ( opts.lecho )
|
||||
map_and_write(STO, opts.emap, c);
|
||||
} else
|
||||
fd_printf(STO, "\x07");
|
||||
}
|
||||
break;
|
||||
@ -698,13 +858,7 @@ loop(void)
|
||||
else if ( n < 0 )
|
||||
fatal("read from term failed: %s", strerror(errno));
|
||||
|
||||
do {
|
||||
n = write(STO, &c, 1);
|
||||
} while ( errno == EAGAIN
|
||||
|| errno == EWOULDBLOCK
|
||||
|| errno == EINTR );
|
||||
if ( n <= 0 )
|
||||
fatal("write to stdout failed: %s", strerror(errno));
|
||||
map_and_write(STO, opts.imap, c);
|
||||
}
|
||||
|
||||
if ( FD_ISSET(tty_fd, &wrset) ) {
|
||||
@ -778,12 +932,25 @@ show_usage(char *name)
|
||||
printf(" --<p>arity o (=odd) | e (=even) | n (=none)\n");
|
||||
printf(" --<d>atabits 5 | 6 | 7 | 8\n");
|
||||
printf(" --<e>scape <char>\n");
|
||||
printf(" --e<c>ho\n");
|
||||
printf(" --no<i>nit\n");
|
||||
printf(" --no<r>eset\n");
|
||||
printf(" --no<l>ock\n");
|
||||
printf(" --<s>end-cmd <command>\n");
|
||||
printf(" --recei<v>e-cmd <command>\n");
|
||||
printf(" --imap <map> (input mappings)\n");
|
||||
printf(" --omap <map> (output mappings)\n");
|
||||
printf(" --emap <map> (local-echo mappings)\n");
|
||||
printf(" --<h>elp\n");
|
||||
printf("<map> is a comma-separated list of one or more of:\n");
|
||||
printf(" crlf : map CR --> LF\n");
|
||||
printf(" crcrlf : map CR --> CR + LF\n");
|
||||
printf(" igncr : ignore CR\n");
|
||||
printf(" lfcr : map LF --> CR\n");
|
||||
printf(" lfcrlf : map LF --> CR + LF\n");
|
||||
printf(" ignlf : ignore LF\n");
|
||||
printf(" bsdel : map BS --> DEL\n");
|
||||
printf(" delbs : map DEL --> BS\n");
|
||||
printf("<?> indicates the equivalent short option.\n");
|
||||
printf("Short options are prefixed by \"-\" instead of by \"--\".\n");
|
||||
}
|
||||
@ -797,7 +964,11 @@ parse_args(int argc, char *argv[])
|
||||
{
|
||||
{"receive-cmd", required_argument, 0, 'v'},
|
||||
{"send-cmd", required_argument, 0, 's'},
|
||||
{"imap", required_argument, 0, 'I' },
|
||||
{"omap", required_argument, 0, 'O' },
|
||||
{"emap", required_argument, 0, 'E' },
|
||||
{"escape", required_argument, 0, 'e'},
|
||||
{"echo", no_argument, 0, 'c'},
|
||||
{"noinit", no_argument, 0, 'i'},
|
||||
{"noreset", no_argument, 0, 'r'},
|
||||
{"nolock", no_argument, 0, 'l'},
|
||||
@ -812,11 +983,12 @@ parse_args(int argc, char *argv[])
|
||||
while (1) {
|
||||
int optionIndex = 0;
|
||||
int c;
|
||||
int map;
|
||||
|
||||
/* no default error messages printed. */
|
||||
opterr = 0;
|
||||
|
||||
c = getopt_long(argc, argv, "hirls:r:e:f:b:p:d:",
|
||||
c = getopt_long(argc, argv, "hirlcv:s:r:e:f:b:p:d:",
|
||||
longOptions, &optionIndex);
|
||||
|
||||
if (c < 0)
|
||||
@ -831,6 +1003,24 @@ parse_args(int argc, char *argv[])
|
||||
strncpy(opts.receive_cmd, optarg, sizeof(opts.receive_cmd));
|
||||
opts.receive_cmd[sizeof(opts.receive_cmd) - 1] = '\0';
|
||||
break;
|
||||
case 'I':
|
||||
map = parse_map(optarg);
|
||||
if (map >= 0) opts.imap = map;
|
||||
else fprintf(stderr, "Invalid imap, ignored\n");
|
||||
break;
|
||||
case 'O':
|
||||
map = parse_map(optarg);
|
||||
if (map >= 0) opts.omap = map;
|
||||
else fprintf(stderr, "Invalid omap, ignored\n");
|
||||
break;
|
||||
case 'E':
|
||||
map = parse_map(optarg);
|
||||
if (map >= 0) opts.emap = map;
|
||||
else fprintf(stderr, "Invalid emap, ignored\n");
|
||||
break;
|
||||
case 'c':
|
||||
opts.lecho = 1;
|
||||
break;
|
||||
case 'i':
|
||||
opts.noinit = 1;
|
||||
break;
|
||||
@ -935,16 +1125,21 @@ parse_args(int argc, char *argv[])
|
||||
printf("parity is : %s\n", opts.parity_str);
|
||||
printf("databits are : %d\n", opts.databits);
|
||||
printf("escape is : C-%c\n", 'a' + opts.escape - 1);
|
||||
printf("local echo is : %s\n", opts.lecho ? "yes" : "no");
|
||||
printf("noinit is : %s\n", opts.noinit ? "yes" : "no");
|
||||
printf("noreset is : %s\n", opts.noreset ? "yes" : "no");
|
||||
printf("nolock is : %s\n", opts.nolock ? "yes" : "no");
|
||||
printf("send_cmd is : %s\n", opts.send_cmd);
|
||||
printf("receive_cmd is : %s\n", opts.receive_cmd);
|
||||
printf("imap is : "); print_map(opts.imap);
|
||||
printf("omap is : "); print_map(opts.omap);
|
||||
printf("emap is : "); print_map(opts.emap);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
Reference in New Issue
Block a user