/* * ascii-xfr Ascii file transfer. * * Usage: ascii-xfr -s|-r [-ednv] [-c character delay] [-l line delay] * * 08.03.98 added a patch from Bo Branten * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_TERMIOS_H #include #endif #include "intl.h" /* * Externals. */ extern int optind; extern char *optarg; /* * Global variables. */ static int cdelay = 0; static int ldelay = 0; static int dotrans = 1; static int eofchar = 26; static int useeof = 0; static int verbose = 0; static time_t start, last; static unsigned long bdone = 0; /* * Millisecond delay. */ static void ms_delay(int ms) { #ifdef HAVE_USLEEP usleep(1000 * ms); #endif } /* * Output a line and delay if needed. */ static void lineout(char const *line, int len) { int ret; if (!cdelay) { do { ret = write(STDOUT_FILENO, line, len); if (ret < 0) { fprintf(stderr, _("Error while writing (errno = %d)\n"), errno); return; } len -= ret; line += ret; } while (len); } else { while (*line) { ret = write(STDOUT_FILENO, line, 1); if (ret < 0) { fprintf(stderr, _("Error while writing (errno = %d)\n"), errno); return; } if (ret == 1) line++; ms_delay(cdelay); } } } /* * Show the up/download statistics. */ static void stats(int force) { time_t now; time_t dif; if (!verbose) return; time(&now); dif = now - start; if (!force && dif < 2) return; if (dif < 1) dif = 1; last = now; fprintf(stderr, _("\r%.1f Kbytes transferred at %d CPS"), (float)bdone / 1024, (int)(bdone / dif)); fflush(stderr); } static void check_answer(void) { /* a patch from Bo Branten */ char line[1024]; int n; fd_set rfds; struct timeval tv; FD_ZERO (&rfds); FD_SET (STDIN_FILENO, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; while (select (STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0) { n = read (STDIN_FILENO, line, sizeof(line)); if (write(STDERR_FILENO, line, n) == -1) break; FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; } } static void flush_output(void) { fflush(stdout); if (isatty(STDOUT_FILENO)) tcdrain(STDOUT_FILENO); } /* * Send a file in ASCII mode. */ static int asend(char *file) { FILE *fp; char line[1024]; char *s; int first = 1; long cur, len; if ((fp = fopen(file, "r")) == NULL) { perror(file); return -1; } cur = 0; while (fgets(line, sizeof(line) - 2, fp) != NULL) { long c = ftell(fp); len = c - cur; cur = c; if (dotrans && (s = strrchr(line, '\n')) != NULL) { /* s now points to \n */ /* if there's a \r before, go there */ if (s > line && *(s - 1) == '\r') { s--; len--; } /* end of line */ *s++ = '\r'; *s++ = '\n'; /* terminate string */ *s = 0; len++; } lineout(line, len); bdone += len; if (ldelay) { flush_output(); ms_delay(ldelay); } stats(first); first = 0; check_answer(); } if (useeof) putchar(eofchar); flush_output(); fclose(fp); return 0; } /* * Receive a file in ASCII mode. */ static int arecv(char *file) { FILE *fp; char line[1024]; char *s; int n; int first = 1; if ((fp = fopen(file, "w")) == NULL) { perror(file); return -1; } while ((n = read(STDIN_FILENO, line, sizeof(line))) > 0) { for (s = line; s - line < n; s++) { if (*s == eofchar) break; if (dotrans && *s == '\r') continue; bdone++; fputc(*s, fp); } stats(first); first = 0; if (s - line < n && *s == eofchar) break; } fclose(fp); return 0; } static void usage(void) { fprintf(stderr, _("\ Usage: ascii-xfr -s|-r [-dvn] [-l linedelay] [-c character delay] filename\n\ -s: send\n\ -r: receive\n\ -e: send the End Of File character (default is not to)\n\ -d: set End Of File character to Control-D (instead of Control-Z)\n\ -v: verbose (statistics on stderr output)\n\ -n: do not translate CRLF <--> LF\n\ Delays are in milliseconds.\n")); exit(1); } int main(int argc, char **argv) { int c; int what = 0; char *file; int ret; while ((c = getopt(argc, argv, "srdevnl:c:")) != EOF) { switch (c) { case 's': case 'r': what = c; break; case 'd': eofchar = 4; /* Unix, CTRL-D */ break; case 'e': useeof = 1; break; case 'v': verbose++; break; case 'n': dotrans = 0; break; case 'l': ldelay = atoi(optarg); break; case 'c': cdelay = atoi(optarg); break; default: usage(); break; } } if (optind != argc - 1 || what == 0) usage(); file = argv[optind]; time(&start); last = start; if (what == 's') { fprintf(stderr, _("ASCII upload of \"%s\"\n"), file); if (cdelay || ldelay) fprintf(stderr, _("Line delay: %d ms, character delay %d ms\n"), ldelay, cdelay); fprintf(stderr, "\n"); fflush(stderr); ret = asend(file); } else { fprintf(stderr, _("ASCII download of \"%s\"\n\n"), file); fflush(stderr); ret = arecv(file); } if (verbose) { stats(1); fprintf(stderr, _("... Done.\n")); fflush(stdout); } return ret < 0 ? 1 : 0; }