Next: Include Files and Callbacks, Previous: Adding Command Line Options, Up: Making Genparse Files [Contents][Index]
Genparse automatically creates command line parsing code, not unlike
the code in mycopy2.c
. It creates two or three files: a header
file, a parsing file, and an optional callback file. In this section,
we’ll write a Genparse specification for our file copying program and
examine the parser that it creates.
Genparse runs on a simple input file, which we’ll call a Genparse file.
In a Genparse file, each command line option is specified on one or more
lines. The following code is a Genparse file for mycopy3
.
/* mycopy3.gp */ i / iterations int 1 [0...] "Number of times to output <file>." "File should be text format!" o / outfile string {""} "Output file name." #usage_begin usage: __PROGRAM_NAME__ __OPTIONS_SHORT__ file Print a file for a number of times to stdout. __GLOSSARY__ #usage_end
The naming of this file follows the convention of all Genparse files
ending in the extension .gp
.
Let’s walk through mycopy3.gp
. The first line is a comment. It
is ignored by Genparse.
The second line is the first option specification. This is the
-i option, which, as before, may be specified in long form as
--iterations. Our mycopy3.gp
file indicates that
-i must take an integer parameter, the default value of which
is 1. The allowed range is non-negative. The final part of the third
line is a description of the option’s usage (to appear in the
usage ()
function).
The third line introduces a new option, that was not in
mycopy2
. The -o option takes a string parameter
(where a "string" is any series of characters) with a default value of
empty. As indicated by the description, this option is used
to specify an output file to which mycopy3
’s output will
be directed.
Default values for strings must be specified within braces and quotes like {"This is a stupid comment"}, for chars it must be enclosed in single quotes, e.g. ’a’ or ’\0x13’. For other integers use the plain default value.
Starting in the third line the help screen is defined which will be
printed if -h or --help is set or if an invalid
command line is given. __PROGRAM_NAME__
will be replaced with
the name of the executable (probably mycopy3), __OPTIONS_SHORT__
will be replaced with a list of allowed short options ("[ -iohv ]" in
this example). "Print a file for a number of times to stdout." will
be printed verbatim. __GLOSSARY__
will be replaced with a list
explanations for each of the command line parameters. For more
explanations on the #usage
section See Usage Function.
mycopy3 --help
will print the following help screen:
usage: mycopy3 [ -iohv ] file Print file for a number of times to stdout. [ -i ] [ --iterations ] (type=INTEGER, range=0..., default=1) Number of times to output <file>. File should be text format! [ -o ] [ --outfile ] (type=STRING) Output file name. [ -h ] [ --help ] (type=FLAG) Display this help and exit. [ -v ] [ --version ] (type=FLAG) Output version information and exit.
Genparse can be invoked on mycopy3.gp
in a number of ways (Yes,
Genparse has its own command line options! See Genparse Options.), but
we’ll invoke it as follows.
genparse -o mycopy3_clp mycopy3.gp
This command tells Genparse to run on mycopy3.gp
and to output
program files named with mycopy3_clp
. This particular Genparse
file creates only a header file and a parser file since no callbacks are
specified. Let’s first take a look at the header file,
mycopy3_clp.h
.
• Header Files: | ||
• Parser Files: | ||
• Main Program: |
Next: Parser Files, Previous: Simplifying Command Line Parsing with Genparse, Up: Simplifying Command Line Parsing with Genparse [Contents][Index]
Below, we walk through mycopy3_clp.h
, an example header file
created by Genparse. Header files, such as this one, must be
included in all linked code that needs to access the command line
parameter values.
/* mycopy3_clp.h */ #include <stdio.h> #ifndef bool typedef enum bool_t { false = 0, true } bool; #endif /* customized structure for command line parameters */ struct arg_t { int i; char * o; bool h; bool v; int optind; }; /* function prototypes */ void Cmdline (struct arg_t *my_args, int argc, char *argv[]); void usage (int status, char *program_name);
Although "real" Genparse output files begin with a section of comments, for purposes of saving space, we’ll replace all of those with a short comment containing only the file’s name.
A Genparse-created header file contains four major sections: (1) includes
and type definitions, (2) the definition of struct arg_t
, (3)
parsing function prototypes, and (4) callback function prototypes. Since
we are not using callbacks in this example, only the first three
sections appear in this header file.
The file begins with a list of header files to include. Including
stdio.h
is the default, and other includes may be specified in
the Genparse file. Then the bool
type is conditionally defined.
While bool
is typically predefined in C++, it is not in C. It
comes in handy as a type for all flag options, which can only be on or
off (true or false).
The struct arg_t
structure contains a variable for each of the
options defined in mycopy3.gp
. This include i
, an
integer, and o
, a character pointer. For C output, all variables
defined to be strings in Genparse files are declared as character
pointers. For C++ output, the C++ string type from the standard C++
library is used.
In addition to the user-defined options, Genparse adds two extra flag
options, -h and -v. The -h option (long form
of --help) will cause the usage ()
function to be called,
and the program to terminate. The -v option (long form of
--version) will be passed back for the calling function to
process. It is intended that the caller will display the program’s
version number if this option is set. Note that if the calling program
does not process the -v flag, its behavior
will not be affected by this flag.
The optind
variable records the value of the optind
static
variable that is used by getopt ()
and getopt_long ()
.
However, Genparse has changed the behavior of this variable slightly.
(See Parser Files.)
The final section of mycopy3_clp.h
consists of function
prototypes for the command line parser Cmdline ()
2, and the usage ()
function.
The Cmdline ()
function is where the meat of Genparse processing
occurs. It takes as arguments a pointer to an arg_t
struct which
will be filled with the values of the options, and argc
and
argv
which should be passed as the main ()
function
receives them. Genparse asumes that arg_t
is a valid pointer to
an arg_t
struct, the calling program is responsible for properly
allocating memory for it. Typically, the parsing function should be
called at the beginning of the program.
The usage function lists the command line options for the program, as
well as any mandatory command line parameters. Once this information is
displayed, the program is terminated. For example, the usage function
output for mycopy3
, as invoked by the -h option, is
as follows:
usage: mycopy3 [ -iohqv ] file [ -i ] [ --iterations ] Number of times to output <file>. (default = 1) [ -o ] [ --outfile ] Output file. [ -h ] [ --help ] Display help information. (default = 0) [ -v ] [ --version ] Output version. (default = 0)
After displaying a brief list of all single-character options and mandatory options, the usage message lists all options in short and long forms, along with user-defined descriptions and each option’s default value.
Next: Main Program, Previous: Header Files, Up: Simplifying Command Line Parsing with Genparse [Contents][Index]
In this section we examine the parser file generated from running
Genparse on mycopy3.gp
.
/* mycopy3_clp.c */ #include <string.h> #include <stdlib.h> #include <getopt.h> #include "mycopy3_clp.h" static struct option const long_options[] = { {"iterations", required_argument, NULL, 'i'}, {"outfile", required_argument, NULL, 'o'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} }; /*---------------------------------------------------------------------------- ** ** Cmdline () ** ** Parse the argv array of command line parameters ** **--------------------------------------------------------------------------*/ void Cmdline (struct arg_t *my_args, int argc, char *argv[]) { extern char *optarg; extern int optind; int c; int errflg = 0; my_args->i = 1; my_args->o = NULL; my_args->h = false; my_args->v = false; optind = 0; while ((c = getopt_long (argc, argv, "i:o:hv", long_options, &optind)) != EOF) { switch (c) { case 'i': my_args->i = atoi (optarg); if (my_args->i < 0) { fprintf (stderr, "parameter range error: i must be >= 0\n"); errflg++; } break; case 'o': my_args->o = optarg; break; case 'h': my_args->h = true; usage (EXIT_SUCCESS, argv[0]); break; case 'v': my_args->v = true; break; default: usage (EXIT_FAILURE, argv[0]); } } /* while */ if (errflg) usage (EXIT_FAILURE, argv[0]); if (optind >= argc) my_args->optind = 0; else my_args->optind = optind; } /*---------------------------------------------------------------------------- ** ** usage () ** ** Print out usage information, then exit ** **--------------------------------------------------------------------------*/ void usage (int status, char *program_name) { if (status != EXIT_SUCCESS) fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else { printf ("\ usage: %s [ -iohv ] file\n\ Print a file for a number of times to stdout.\n\ [ -i ] [ --iterations ] (type=INTEGER, range=0..., default=1)\n\ Number of times to output <file>.\n\ File should be text format!\n\ [ -o ] [ --outfile ] (type=STRING)\n\ Output file name.\n\ [ -h ] [ --help ] (type=FLAG)\n\ Display this help and exit.\n\ [ -v ] [ --version ] (type=FLAG)\n\ Output version information and exit.\n", program_name); } exit (status); }
The parser file consists of two main functions. The usage ()
function displays the program’s usage information, then terminates.
The parsing function, named Cmdline ()
in this
case3, reads the command line and fills an
arg_t
struct with the command line parameters.
Since the usage ()
function is straightforward, we will not examine
it in detail. Instead, we will focus our attention on Cmdline ()
.
This function begins by defining a struct long_options
array based
on the specification in the mycopy3.gp
file. This array will tell
getopt_long ()
what options to expect on the command line. The
struct arg_t
is then initialized and the default parameter values
from mycopy3.gp
are set. Once this is complete,
getopt_long ()
is looped through until all command line options have
been processed. Each option has its own case
in the switch
statement. While this processing is fairly simple, there are several
options worth examining in more detail.
usage ()
function is automatically called.
After the loop over getopt_long ()
is complete, the error flag
is checked. If it is raised, or if the help option has been set, the
usage ()
function is called.
At the end of Cmdline ()
, the behavior of optind
is
modified slightly. While optind
is returned to the caller in the
struct arg_t
, we set it to 0 if there are no non-option command
line parameters. Otherwise, we pass it back as is, so that it can be
used as a pointer into argv
.
Previous: Parser Files, Up: Simplifying Command Line Parsing with Genparse [Contents][Index]
Next to specification of the Genparse file, the most important part of
using Genparse is interfacing it with user code. In this section, we
show the main program code for mycopy3.c
and describe how
the routines created by Genparse are used.
/* mycopy3.c */ #include <stdio.h> #include <stdlib.h> #include "mycopy3_clp.h" #define VERSION "3.0" int main (int argc, char *argv[]) { int c, i; FILE *fp, *ofp; struct arg_t a; Cmdline (&a, argc, argv); if (a.v) { printf ("%s version %s\n", argv[0], VERSION); exit (0); } if (a.o) ofp = fopen (a.o, "w"); else ofp = stdout; if (!a.optind) fp = stdin; else fp = fopen (argv[a.optind],"r"); for (i = 0; i < a.i; i++) { while ((c = fgetc (fp)) != EOF) fputc (c, ofp); rewind (fp); } fclose (fp); return 0; }
The mycopy3.c
module begins by including mycopy3_clp.h
,
which is necessary for the definition of the arg_t
struct and
the parser function prototypes. The Cmdline ()
function fills an
arg_t
struct with the command line options. While the parsing
function does not always have to be called before all other processing,
it must be called before any command line parameters are used.
The program then checks a number of the parameters, as returned in the structure. In particular, if the -v option is set, the version number is displayed and then the program is terminated.
If the optind
pointer is set to 0, indicating that there are no
non-option parameters on the command line, the input is redirected to
stdin, If the output file is not specified with the -o
option, output is redirected to stdout.
The name of the command line parsing function can be user-defined. See Genparse Options.
The name of the parser function can be set by the user. See Genparse Options.
Previous: Parser Files, Up: Simplifying Command Line Parsing with Genparse [Contents][Index]