Command-line parsing that doesn't depend on getopt()

This commit is contained in:
hpa 2004-01-08 20:47:00 +00:00
parent b38a61cf70
commit 0eea078aec
3 changed files with 92 additions and 64 deletions

View file

@ -183,19 +183,36 @@ char *tail(char *);
char *xstrdup(const 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct sockaddr_in s_in; struct sockaddr_in s_in;
int o; int arg;
int pargc; static int pargc, peerargc;
int iscmd = 0; static int iscmd = 0;
char **pargv; char **pargv;
const char *optx;
char *peerargv[3];
program = argv[0];
mode = MODE_DEFAULT; mode = MODE_DEFAULT;
while ((o = getopt(argc, argv, "chm:Vv")) != -1) { peerargv[0] = argv[0];
switch (o) { peerargc = 1;
for ( arg = 1 ; !iscmd && arg < argc ; arg++ ) {
if ( argv[arg][0] == '-' ) {
for ( optx = &argv[arg][1] ; *optx ; optx++ ) {
switch ( *optx ) {
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
@ -204,17 +221,19 @@ main(int argc, char *argv[])
printf("%s\n", TFTP_CONFIG_STR); printf("%s\n", TFTP_CONFIG_STR);
exit(0); exit(0);
case 'm': case 'm':
if ( ++arg >= argc )
usage(EX_USAGE);
{ {
const struct modes *p; const struct modes *p;
for ( p = modes ; p->m_name ; p++ ) { for ( p = modes ; p->m_name ; p++ ) {
if (!strcmp(optarg, p->m_name)) if (!strcmp(argv[arg], p->m_name))
break; break;
} }
if (p->m_name) { if (p->m_name) {
settftpmode(p); settftpmode(p);
} else { } else {
fprintf(stderr, "%s: invalid mode: %s\n", argv[0], optarg); fprintf(stderr, "%s: invalid mode: %s\n", argv[0], argv[arg]);
exit(EX_USAGE); exit(EX_USAGE);
} }
} }
@ -224,13 +243,19 @@ main(int argc, char *argv[])
break; break;
case 'h': case 'h':
default: default:
fprintf(stderr, "Usage: %s [-v][-m mode] [-c command|host]\n", argv[0]); usage(*optx == 'h' ? 0 : EX_USAGE);
exit(o == 'h' ? 0 : EX_USAGE); }
}
} else {
if ( peerargc >= 3 )
usage(EX_USAGE);
peerargv[peerargc++] = argv[arg];
} }
} }
pargc = argc - (optind-1); pargv = argv + arg;
pargv = argv + (optind-1); pargc = argc - arg;
sp = getservbyname("tftp", "udp"); sp = getservbyname("tftp", "udp");
if (sp == 0) { if (sp == 0) {
@ -256,27 +281,28 @@ main(int argc, char *argv[])
exit(EX_OSERR); exit(EX_OSERR);
} }
bsd_signal(SIGINT, intr); bsd_signal(SIGINT, intr);
if (pargc > 1) {
if ( iscmd ) { if ( peerargc ) {
/* Set peer */
if (sigsetjmp(toplevel,1) != 0)
exit(EX_NOHOST);
setpeer(peerargc, peerargv);
}
if ( iscmd && pargc ) {
/* -c specified; execute command and exit */ /* -c specified; execute command and exit */
struct cmd *c; struct cmd *c;
if (sigsetjmp(toplevel,1) != 0) if (sigsetjmp(toplevel,1) != 0)
exit(EX_UNAVAILABLE); exit(EX_UNAVAILABLE);
c = getcmd(pargv[1]); c = getcmd(pargv[0]);
if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) {
fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]); fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]);
exit(EX_USAGE); exit(EX_USAGE);
} }
(*c->handler)(pargc-1, pargv+1); (*c->handler)(pargc, pargv);
exit(0); exit(0);
} else {
/* No -c */
if (sigsetjmp(toplevel,1) != 0)
exit(0);
setpeer(pargc, pargv);
}
} }
if (sigsetjmp(toplevel,1) != 0) if (sigsetjmp(toplevel,1) != 0)
(void)putchar('\n'); (void)putchar('\n');

View file

@ -37,8 +37,9 @@
\- IPv4 Trivial File Transfer Protocol client \- IPv4 Trivial File Transfer Protocol client
.SH SYNOPSIS .SH SYNOPSIS
.B tftp .B tftp
.RI [ options... ] [ \fIoptions...\fP ]
.RI [ host ] [\fIhost\fP [\fIport\fP]]
[\fB\-c\fP \fIcommand\fP]
.br .br
.SH DESCRIPTION .SH DESCRIPTION
.B tftp .B tftp
@ -57,6 +58,7 @@ command below.)
.TP .TP
\fB\-c\fP \fIcommand\fP \fB\-c\fP \fIcommand\fP
Execute \fIcommand\fP as if it had been entered on the tftp prompt. Execute \fIcommand\fP as if it had been entered on the tftp prompt.
Must be specified last on the command line.
.TP .TP
\fB\-m\fP \fImode\fP \fB\-m\fP \fImode\fP
Set the default transfer mode to \fImode\fP. This is usually used with \-c. Set the default transfer mode to \fImode\fP. This is usually used with \-c.

View file

@ -421,14 +421,14 @@ static void
printstats(const char *direction, unsigned long amount) printstats(const char *direction, unsigned long amount)
{ {
double delta; double delta;
/* compute delta in 1/10's second units */
delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -
((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); (tstart.tv_sec+(tstart.tv_usec/100000.0));
delta = delta/10.; /* back to seconds */ if (verbose) {
printf("%s %lu bytes in %.1f seconds", direction, amount, delta); printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
if (verbose) printf(" [%.0f bit/s]", (amount*8.)/delta);
printf(" [%.0f bits/sec]", (amount*8.)/delta);
putchar('\n'); putchar('\n');
}
} }
static void static void