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

View file

@ -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.

View file

@ -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 */
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);
if (verbose)
printf(" [%.0f bits/sec]", (amount*8.)/delta);
printf(" [%.0f bit/s]", (amount*8.)/delta);
putchar('\n');
}
}
static void