Back to Operating Systems Home Page
Next: Automatic assignment submission program
Up: 1997 term messages
Previous: Additional Instructions (Assig. 1)
As requested from several students, I put together a sample code fragment
using getopt(3) to parse the command line argument of a command.
Note: it's pointless to read the following code unless you have already
gone through the manpage, and the simple examples shown there. What
follows belongs to the "fairly hairy" category.
The code refers to the processing of the command-line options for the
ar(1V) command. From its manpage (SunOS 4.1) we gather the following
synopsis:
----------------
AR(1V) USER COMMANDS AR(1V)
NAME
ar - create library archives, and add or extract files
SYNOPSIS
ar {-d|m|p|q|r|t|x}[[-clouv][-abi position-name]] archive [ member-file...]
---------------
Meaning:
1) One and only one of the d,m,p,q,r,t,x options must be specified;
2) options c,l,o,u,v do not take any arguments, and may be specified
together;
3) if one or more of the c,l.o,u,v options are specified, then one or
more of the a,b,i options may be specified, each taking a string
argument.
4) Other than options, the command take as arguments an "archive"
name, and a list of "member-file" names.
Note that not all options take arguments. Note also that getopt(3) can be used
only to parse the command-line options, while the remaining command-line
arguments (4) must be read directly on argv[].
This synopsis might be parsed by a main like the following:
/*
// ar.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
/* usage: print help message and abort. */
void
usage(void) {
fprintf(stderr,
"Usage:\n"
"ar {- d | m | p | q | r | t | x} [ [ clouv ] \n"
"[ abi position-name] ] archive [ member-file... ]\n");
exit(1);
}
int
main(int argc, char* argv[]) {
extern char *optarg;
extern int optind;
void usage(void);
/* Variables used for option-parsing. */
int c; /* Option character returned by getopt(3). Must be declared as an
int because at the end of the options getopt returns -1. */
int cmd=0; /* Used to detect whether one and only one of the compulsory
directives d,m,p,q,r,t,x has been passed, and which one. */
char optformat[]="dmpqrtxclouva:b:i:"; /* Option format string to pass to
getopt: note that options a,b,i
are specified as needing an
argument. */
int clouv=0; /* True if one or more of the c,l,o,u,v options have been
passed. */
int op_c=0, op_l=0, op_o=0,
op_u=0, op_v=0; /* True when the corresponding options have been
passed. */
char* posname[3]={NULL, NULL, NULL}; /* Arguments passed to options
a,b,i, in this order. NULL means
option not passed. */
char *archive=NULL, **member_files=NULL;
int member_num=0; /* Number of member_files passed. */
/* Parse command line */
while (-1 != (c=getopt(argc, argv, optformat))) {
switch (c) {
case 'd': /* All compulsory arguments first */
case 'm':
case 'p':
case 'q':
case 'r':
case 't':
case 'x':
if (cmd) usage(); /* one and only one... */
else cmd=c;
break;
case 'c':
op_c=clouv=1;
break;
case 'l':
op_l=clouv=1;
break;
case 'o':
op_o=clouv=1;
break;
case 'u':
op_u=clouv=1;
break;
case 'v':
op_v=clouv=1;
break;
case 'a':
/* a,b,i are legal only after c,l,o,u, or v are passed */
if (!clouv) usage();
/* Copy option argument by strdup(3).*/
posname[0]=strdup(optarg);
break;
case 'b':
if (!clouv) usage();
posname[1]=strdup(optarg);
break;
case 'i':
if (!clouv) usage();
posname[2]=strdup(optarg);
break;
default: /* Bad option passed */
usage();
}
}
/* Now get the archive and member_file arguments
After getopt finishes parsing successfully,
optind indexes the first non-option argument
But we must check whether it's actually there
or not, since the "archive"argument is compulsory. */
if (optind==argc) usage(); /* oops, no archive passed: abort . */
archive=argv[optind++];
/* Are there any member_files? */
if (argc>optind) {
/* Make room for at least one of them */
member_files=(char**)malloc(sizeof(char*));
assert(member_files); /* Abort via assert(3) if allocation failed. */
while (argc>optind) {
if (member_num>0) { /* We need more room */
member_files=(char**)realloc(member_files,
member_num*sizeof(char*));
assert(member_files);
}
member_files[member_num++]=strdup(argv[optind++]);
}
}
/* Command line done - now get the job done ... */
/* THE JOB SHOULD GET DONE HERE, but that's left as an exercise ;-) */
}
\
Franco Callari