From 0eea078aece1b1b945c7f74dc3230dc9834826a6 Mon Sep 17 00:00:00 2001 From: hpa Date: Thu, 8 Jan 2004 20:47:00 +0000 Subject: [PATCH] Command-line parsing that doesn't depend on getopt() --- tftp/main.c | 134 +++++++++++++++++++++++++++++-------------------- tftp/tftp.1.in | 6 ++- tftp/tftp.c | 16 +++--- 3 files changed, 92 insertions(+), 64 deletions(-) diff --git a/tftp/main.c b/tftp/main.c index 661796c..961c0c4 100644 --- a/tftp/main.c +++ b/tftp/main.c @@ -183,54 +183,79 @@ char *tail(char *); char *xstrdup(const char *); +const char *program; + +static inline void usage(int errcode) +{ + fprintf(stderr, "Usage: %s [-v][-m mode] [host [port]] [-c command]\n", program); + exit(errcode); +} + int main(int argc, char *argv[]) { struct sockaddr_in s_in; - int o; - int pargc; - int iscmd = 0; + int arg; + static int pargc, peerargc; + static int iscmd = 0; char **pargv; + const char *optx; + char *peerargv[3]; + + program = argv[0]; mode = MODE_DEFAULT; - - while ((o = getopt(argc, argv, "chm:Vv")) != -1) { - switch (o) { - case 'v': - verbose = 1; - break; - case 'V': - /* Print version and configuration to stdout and exit */ - printf("%s\n", TFTP_CONFIG_STR); - exit(0); - case 'm': - { - const struct modes *p; - for ( p = modes ; p->m_name ; p++ ) { - if (!strcmp(optarg, p->m_name)) - break; - } - if (p->m_name) { - settftpmode(p); - } else { - fprintf(stderr, "%s: invalid mode: %s\n", argv[0], optarg); - exit(EX_USAGE); + peerargv[0] = argv[0]; + peerargc = 1; + + for ( arg = 1 ; !iscmd && arg < argc ; arg++ ) { + if ( argv[arg][0] == '-' ) { + for ( optx = &argv[arg][1] ; *optx ; optx++ ) { + switch ( *optx ) { + case 'v': + verbose = 1; + break; + case 'V': + /* Print version and configuration to stdout and exit */ + printf("%s\n", TFTP_CONFIG_STR); + exit(0); + case 'm': + if ( ++arg >= argc ) + usage(EX_USAGE); + { + const struct modes *p; + + for ( p = modes ; p->m_name ; p++ ) { + if (!strcmp(argv[arg], p->m_name)) + break; + } + if (p->m_name) { + settftpmode(p); + } else { + fprintf(stderr, "%s: invalid mode: %s\n", argv[0], argv[arg]); + exit(EX_USAGE); + } + } + break; + case 'c': + iscmd = 1; + break; + case 'h': + default: + usage(*optx == 'h' ? 0 : EX_USAGE); } } - break; - case 'c': - iscmd = 1; - break; - case 'h': - default: - fprintf(stderr, "Usage: %s [-v][-m mode] [-c command|host]\n", argv[0]); - exit(o == 'h' ? 0 : EX_USAGE); + } else { + if ( peerargc >= 3 ) + usage(EX_USAGE); + + peerargv[peerargc++] = argv[arg]; } } - pargc = argc - (optind-1); - pargv = argv + (optind-1); + pargv = argv + arg; + pargc = argc - arg; sp = getservbyname("tftp", "udp"); if (sp == 0) { @@ -256,27 +281,28 @@ main(int argc, char *argv[]) exit(EX_OSERR); } bsd_signal(SIGINT, intr); - if (pargc > 1) { - if ( iscmd ) { - /* -c specified; execute command and exit */ - struct cmd *c; - if (sigsetjmp(toplevel,1) != 0) - exit(EX_UNAVAILABLE); + if ( peerargc ) { + /* Set peer */ + if (sigsetjmp(toplevel,1) != 0) + exit(EX_NOHOST); + setpeer(peerargc, peerargv); + } - c = getcmd(pargv[1]); - if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { - fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]); - exit(EX_USAGE); - } - (*c->handler)(pargc-1, pargv+1); - exit(0); - } else { - /* No -c */ - if (sigsetjmp(toplevel,1) != 0) - exit(0); - setpeer(pargc, pargv); - } + if ( iscmd && pargc ) { + /* -c specified; execute command and exit */ + struct cmd *c; + + if (sigsetjmp(toplevel,1) != 0) + exit(EX_UNAVAILABLE); + + c = getcmd(pargv[0]); + if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { + fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]); + exit(EX_USAGE); + } + (*c->handler)(pargc, pargv); + exit(0); } if (sigsetjmp(toplevel,1) != 0) (void)putchar('\n'); diff --git a/tftp/tftp.1.in b/tftp/tftp.1.in index 9994cf4..9ba9a85 100644 --- a/tftp/tftp.1.in +++ b/tftp/tftp.1.in @@ -37,8 +37,9 @@ \- IPv4 Trivial File Transfer Protocol client .SH SYNOPSIS .B tftp -.RI [ options... ] -.RI [ host ] +[ \fIoptions...\fP ] +[\fIhost\fP [\fIport\fP]] +[\fB\-c\fP \fIcommand\fP] .br .SH DESCRIPTION .B tftp @@ -57,6 +58,7 @@ command below.) .TP \fB\-c\fP \fIcommand\fP Execute \fIcommand\fP as if it had been entered on the tftp prompt. +Must be specified last on the command line. .TP \fB\-m\fP \fImode\fP Set the default transfer mode to \fImode\fP. This is usually used with \-c. diff --git a/tftp/tftp.c b/tftp/tftp.c index 0e615e5..475d25b 100644 --- a/tftp/tftp.c +++ b/tftp/tftp.c @@ -421,14 +421,14 @@ static void printstats(const char *direction, unsigned long amount) { double delta; - /* compute delta in 1/10's second units */ - delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - - ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); - delta = delta/10.; /* back to seconds */ - printf("%s %lu bytes in %.1f seconds", direction, amount, delta); - if (verbose) - printf(" [%.0f bits/sec]", (amount*8.)/delta); - putchar('\n'); + + delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) - + (tstart.tv_sec+(tstart.tv_usec/100000.0)); + if (verbose) { + printf("%s %lu bytes in %.1f seconds", direction, amount, delta); + printf(" [%.0f bit/s]", (amount*8.)/delta); + putchar('\n'); + } } static void