chat: update by Vladimir 1) to treat timeout more correctly (timeout affects whole send command duration, not a single char); 2) to recognize RECORD directive.
No binary (build failed)
—
(log yok)
| @@ -9,16 +9,6 @@ | |
| */ | |
| #include "libbb.h" | |
| - | /* |
| - | #define ENABLE_FEATURE_CHAT_NOFAIL 1 // +126 bytes |
| - | #define ENABLE_FEATURE_CHAT_TTY_HIFI 0 // + 70 bytes |
| - | #define ENABLE_FEATURE_CHAT_IMPLICIT_CR 1 // + 44 bytes |
| - | #define ENABLE_FEATURE_CHAT_SEND_ESCAPES 0 // +103 bytes |
| - | #define ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 0 // + 70 bytes |
| - | #define ENABLE_FEATURE_CHAT_CLR_ABORT 0 // +113 bytes |
| - | #define ENABLE_FEATURE_CHAT_SWALLOW_OPTS 0 // + 23 bytes |
| - | */ |
| - | |
| // default timeout: 45 sec | |
| #define DEFAULT_CHAT_TIMEOUT 45*1000 | |
| // max length of "abort string", | |
| @@ -37,8 +27,7 @@ enum { | |
| }; | |
| // exit code | |
| - | // N.B> 10 bytes for volatile. Why all these signals?! |
| - | static /*volatile*/ smallint exitcode; |
| + | #define exitcode bb_got_signal |
| // trap for critical signals | |
| static void signal_handler(UNUSED_PARAM int signo) | |
| @@ -101,13 +90,10 @@ static size_t unescape(char *s, int *nocr) | |
| return p - start; | |
| } | |
| - | |
| int chat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int chat_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| - | // should we dump device output? to what fd? by default no. |
| - | // this can be controlled later via ECHO {ON|OFF} chat directive |
| - | // int echo_fd; |
| + | int record_fd = -1; |
| bool echo = 0; | |
| // collection of device replies which cause unconditional termination | |
| llist_t *aborts = NULL; | |
| @@ -132,6 +118,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| DIR_TIMEOUT, | |
| DIR_ECHO, | |
| DIR_SAY, | |
| + | DIR_RECORD, |
| }; | |
| // make x* functions fail with correct exitcode | |
| @@ -166,14 +153,14 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| #if ENABLE_FEATURE_CHAT_CLR_ABORT | |
| "CLR_ABORT\0" | |
| #endif | |
| - | "TIMEOUT\0" "ECHO\0" "SAY\0" |
| + | "TIMEOUT\0" "ECHO\0" "SAY\0" "RECORD\0" |
| , *argv | |
| ); | |
| if (key >= 0) { | |
| // cache directive value | |
| char *arg = *++argv; | |
| - | // ON -> 1, anything else -> 0 |
| - | bool onoff = !strcmp("ON", arg); |
| + | // OFF -> 0, anything else -> 1 |
| + | bool onoff = (0 != strcmp("OFF", arg)); |
| // process directive | |
| if (DIR_HANGUP == key) { | |
| // turn SIGHUP on/off | |
| @@ -217,14 +204,20 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| timeout = DEFAULT_CHAT_TIMEOUT; | |
| } else if (DIR_ECHO == key) { | |
| // turn echo on/off | |
| - | // N.B. echo means dumping output |
| - | // from stdin (device) to stderr |
| + | // N.B. echo means dumping device input/output to stderr |
| echo = onoff; | |
| - | //TODO? echo_fd = onoff * STDERR_FILENO; |
| - | //TODO? echo_fd = xopen(arg, O_WRONLY|O_CREAT|O_TRUNC); |
| + | } else if (DIR_RECORD == key) { |
| + | // turn record on/off |
| + | // N.B. record means dumping device input to a file |
| + | // close previous record_fd |
| + | if (record_fd > 0) |
| + | close(record_fd); |
| + | // N.B. do we have to die here on open error? |
| + | record_fd = (onoff) ? xopen(arg, O_WRONLY|O_CREAT|O_TRUNC) : -1; |
| } else if (DIR_SAY == key) { | |
| // just print argument verbatim | |
| - | fprintf(stderr, arg); |
| + | // TODO: should we use full_write() to avoid unistd/stdio conflict? |
| + | bb_error_msg("%s", arg); |
| } | |
| // next, please! | |
| argv++; | |
| @@ -288,12 +281,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| // read next char from device | |
| if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { | |
| - | // dump device output if ECHO ON or RECORD fname |
| - | //TODO? if (echo_fd > 0) { |
| - | //TODO? full_write(echo_fd, buf+buf_len, 1); |
| - | //TODO? } |
| - | if (echo > 0) |
| + | // dump device input if RECORD fname |
| + | if (record_fd > 0) { |
| + | full_write(record_fd, buf+buf_len, 1); |
| + | } |
| + | // dump device input if ECHO ON |
| + | if (echo > 0) { |
| + | // if (buf[buf_len] < ' ') { |
| + | // full_write(STDERR_FILENO, "^", 1); |
| + | // buf[buf_len] += '@'; |
| + | // } |
| full_write(STDERR_FILENO, buf+buf_len, 1); | |
| + | } |
| buf_len++; | |
| // move input frame if we've reached higher bound | |
| if (buf_len > COMMON_BUFSIZE) { | |
| @@ -320,7 +319,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) | |
| goto expect_done; | |
| #undef buf | |
| - | } |
| + | } /* while (have data) */ |
| // device timed out or unexpected reply received | |
| exitcode = ERR_TIMEOUT; | |
| @@ -365,21 +364,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| trim(++buf); | |
| buf = loaded = xmalloc_xopen_read_close(buf, NULL); | |
| } | |
| - | |
| // expand escape sequences in command | |
| len = unescape(buf, &nocr); | |
| // send command | |
| - | #if ENABLE_FEATURE_CHAT_SEND_ESCAPES |
| + | alarm(timeout); |
| pfd.fd = STDOUT_FILENO; | |
| pfd.events = POLLOUT; | |
| while (len && !exitcode | |
| - | && poll(&pfd, 1, timeout) > 0 |
| + | && poll(&pfd, 1, -1) > 0 |
| && (pfd.revents & POLLOUT) | |
| ) { | |
| - | // ugly! ugly! ugly! |
| - | // gotta send char by char to achieve this! |
| - | // Brrr... |
| + | #if ENABLE_FEATURE_CHAT_SEND_ESCAPES |
| // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay | |
| // "\\K" means send BREAK | |
| char c = *buf; | |
| @@ -389,31 +385,28 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| sleep(1); | |
| len--; | |
| continue; | |
| - | } else if ('p' == c) { |
| + | } |
| + | if ('p' == c) { |
| usleep(10000); | |
| len--; | |
| continue; | |
| - | } else if ('K' == c) { |
| + | } |
| + | if ('K' == c) { |
| tcsendbreak(STDOUT_FILENO, 0); | |
| len--; | |
| continue; | |
| - | } else { |
| - | buf--; |
| } | |
| + | buf--; |
| } | |
| - | if (safe_write(STDOUT_FILENO, buf, 1) > 0) { |
| - | len--; |
| - | buf++; |
| - | } else |
| + | if (safe_write(STDOUT_FILENO, buf, 1) != 1) |
| break; | |
| - | } |
| + | len--; |
| + | buf++; |
| #else | |
| - | // if (len) { |
| - | alarm(timeout); |
| len -= full_write(STDOUT_FILENO, buf, len); | |
| - | alarm(0); |
| - | // } |
| #endif | |
| + | } /* while (can write) */ |
| + | alarm(0); |
| // report I/O error if there still exists at least one non-sent char | |
| if (len) | |
| @@ -427,14 +420,12 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| else if (!nocr) | |
| xwrite(STDOUT_FILENO, "\r", 1); | |
| #endif | |
| - | |
| // bail out unless we sent command successfully | |
| if (exitcode) | |
| break; | |
| - | |
| - | } |
| + | } /* if (*argv) */ |
| } | |
| - | } |
| + | } /* while (*argv) */ |
| #if ENABLE_FEATURE_CHAT_TTY_HIFI | |
| tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); | |