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,54 +183,79 @@ 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) {
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++ ) { peerargv[0] = argv[0];
if (!strcmp(optarg, p->m_name)) peerargc = 1;
break;
} for ( arg = 1 ; !iscmd && arg < argc ; arg++ ) {
if (p->m_name) { if ( argv[arg][0] == '-' ) {
settftpmode(p); for ( optx = &argv[arg][1] ; *optx ; optx++ ) {
} else { switch ( *optx ) {
fprintf(stderr, "%s: invalid mode: %s\n", argv[0], optarg); case 'v':
exit(EX_USAGE); 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; } else {
case 'c': if ( peerargc >= 3 )
iscmd = 1; usage(EX_USAGE);
break;
case 'h': peerargv[peerargc++] = argv[arg];
default:
fprintf(stderr, "Usage: %s [-v][-m mode] [-c command|host]\n", argv[0]);
exit(o == 'h' ? 0 : EX_USAGE);
} }
} }
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 ) {
/* -c specified; execute command and exit */
struct cmd *c;
if (sigsetjmp(toplevel,1) != 0) if ( peerargc ) {
exit(EX_UNAVAILABLE); /* Set peer */
if (sigsetjmp(toplevel,1) != 0)
exit(EX_NOHOST);
setpeer(peerargc, peerargv);
}
c = getcmd(pargv[1]); if ( iscmd && pargc ) {
if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { /* -c specified; execute command and exit */
fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]); struct cmd *c;
exit(EX_USAGE);
} if (sigsetjmp(toplevel,1) != 0)
(*c->handler)(pargc-1, pargv+1); exit(EX_UNAVAILABLE);
exit(0);
} else { c = getcmd(pargv[0]);
/* No -c */ if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) {
if (sigsetjmp(toplevel,1) != 0) fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]);
exit(0); exit(EX_USAGE);
setpeer(pargc, pargv); }
} (*c->handler)(pargc, pargv);
exit(0);
} }
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