Next: Simplifying Command Line Parsing with Genparse, Previous: A Simple Application, Up: Making Genparse Files [Contents][Index]
From the previous section’s mycopy1
, we will now add command
line option parsing with getopt_long ()
to create
mycopy2
. Along the way we’ll add a small number of useful
features.
/* mycopy2.c */ #include <stdio.h> #include <stdlib.h> #include <getopt.h> int main (int argc, char *argv[]) { int c, i; FILE *fp; extern char *optarg; extern int optind; int option_index = 0; char ch; int help, iterations; int errflg = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"iterations", required_argument, NULL, 'i'}, {NULL, 0, NULL, 0} }; help = 0; iterations = 1; while ((ch = getopt_long (argc, argv, "hi:", long_options, &option_index)) != EOF) { switch (ch) { case 'h': help = 1; break; case 'i': iterations = atoi (optarg); if (iterations < 0) { fprintf (stderr, "error: iterations must be >= 0\n"); errflg ++; } break; default: errflg++; } } /* while */ if (errflg || help) { printf ("usage: %s [ -i ] <file>\n", argv[0]); printf (" [ -h ] [ --help ] Print help screen \n"); printf (" [ -i ] [ --iterations ] Number of times to \ output <file>\n"); exit (1); } if (optind >= argc) fp = stdin; else fp = fopen (argv[optind],"r"); for (i = 0; i < iterations; i++) { while ((c = fgetc (fp)) != EOF) fputc (c, stdout); rewind (fp); } fclose (fp); return 0; }
This program performs the same function as mycopy1
but does so
in a more flexible and reliable fashion. Two command line options are
supported, -h and -i. When -h, or its long
form, --help, appears on the command line, all other options
are ignored and a usage message is displayed. The -i option
allows the user to specify the number of iterations, as discussed above.
It also has a long form, --iterations. The number of
iterations defaults to 1 if -i does not appear on the command
line, and the program prevents negative values from being specified with
-i.
The usage message is a useful way of summarizing a program’s options
without needed a man
or info
page. There are three
ways that the usage message for mycopy2
will be displayed:
A nice feature of getopt ()
and getopt_long ()
is that they
will rearrange the command line within argv
so that all
non-options follow all of the options1. The external variable
optind
is set to point to the first non-option in the re-arranged
argv
. Thus, by comparing optind
to argc
, we can
determine whether or not an input file has been specified. If there is
no input file on the command line, we can redirect mycopy2
to
use stdin.
While mycopy2
is an improvement over mycopy1
,
there are a number of drawbacks to using getopt ()
in all
of your programs. The most obvious is time. In mycopy2
,
two-thirds (about 50 lines) of the code does the command line parsing,
and only two options are supported. If there we’re 10 options, the
command line parsing code could easily reach 200 lines or more.
Additionally, since each option’s parameter may need to be checked
for validity and assigned to a variable, this becomes a tedious
process that can be error prone.
Observing the source code for mycopy2
, it becomes clear that,
like any repetitive task, the command line parsing code follows
a number of simple patterns. If these patterns can be abstracted and
generalized so that the user can indicate option use in a concise format,
most, if not all, of the parsing code can be automatically generated.
With this thought in mind, we turn our attention to Genparse.
Next: Simplifying Command Line Parsing with Genparse, Previous: A Simple Application, Up: Making Genparse Files [Contents][Index]