home *** CD-ROM | disk | FTP | other *** search
- /*
-
- cmdln.cpp
- 3-8-91
- Command line option parser
-
- Copyright 1991
- John W. Small
- All rights reserved
- Use freely but acknowledge authorship and copyright.
- CIS: 73757,2233
-
- PSW / Power SoftWare
- P.O. Box 10072
- McLean, Virginia 22102 8072
- (703) 759-3838
-
-
-
- Notes:
-
-
- 1. Call getOption() repeatedly to parse command
- line arguments. The options to look for along with
- the argc and argv must be passed as parameters to
- the constructor CmdLn() or the member function
- CmdLnReset(). The options string is a string of
- the option characters that may appear on your
- programs command line after the switch character,
- '/' or '-' for DOS. If an option takes argument
- then a colon must immediately follow that option
- character in the options string to let
- getOption() know to look for the argument. The
- syntax for the option string is as follows:
-
- options string ::= {optch[:]}*
-
- Your read the syntax as: An options string is zero
- or more (the "*" indicates this) option characters
- any of which may be followed by a colon to indicate
- that the option has an argument.
-
-
- 2. GetOption() returns the current option
- character being processed along with any argument
- in the variable optArg. OptArg is valid only
- when an option requiring an argument is processed.
- If the argument is missing then optArg == 0. If
- the current option character being processed is
- unrecognized, i.e. not in the options string passed
- to CmdLn(), then getOption() returns '?' with
- the unrecognized character stored in optNot. This
- is the only time that optNot is valid!
- getOption() returns -1 when there are no more
- options to process. The variable, optCh,
- maintains a copy of the latest value returned by
- getOption().
-
-
- 3. When your program is invoked, getOption()
- recognizes clusters of command line options. A
- cluster is the switch character followed immediately
- by any number of option characters, no white space.
- The options clusters must preceed any other command
- line parameters since getOption() stops processing
- on the first parameter that is not a switch. This
- is the Unix convention. If you would like to be
- able to intersperse command line switches with other
- parameters on the command line then call
- lookForMoreOptions() to reenable getOption()
- to continue looking for more options. If an option
- takes an argument then the option's character must
- be the last option in the cluster with the argument
- immediately following or separated by white space.
- The argument must not have any white space, though
- it may contain the switch character.
-
- command line option cluster ::=
-
- {'/'|'-'}{[optch]*argch[whitespace]argument}|optch+
-
- Wow! That reads: a command line option cluster
- starts with the switch character ('/' or '-' in DOS)
- with one or more option characters (+ means one or
- more) or (| means or) any number of option
- characters, only the last of which is allowed to
- take an argument. The argument can be either tacked
- on to the end of the option cluster or stand off by
- itself. In either case, argument contains no white
- space! If a switch character appears in a cluster
- by itself or if two switch characters lead off a
- cluster then no more options are processed and the
- next parameter starts the non switched arguments.
- This allows the first non switched argument to start
- with the switch character, i.e. let the preceeding
- cluster be either a single switch character or lead
- off with two switch characters. The switch
- characters are defined in the static variable:
- switches. Switches is currently defined for MS DOS.
-
-
- 4. For example, if the options string contains
- "C:af:z" then 'C' and 'f' take arguments. A valid
- command line would be:
-
- cmd /afnew /zC cmdfile outfile
-
- with repeated calls to getOption() returning:
-
- 'a'
- 'f' with optArg == "new"
- 'z'
- 'C' with optArg == "cmdfile"
- -1 with Argi() == 4
-
- The variable, argi, is the index into the next
- unprocessed argv cell. You can use Argi() to
- initialize your index into the non-switched
- command line parameters.
-
-
- 5. Compile and run cmdln.cpp by defining
- TEST_CMDLN_CPP towards the end of this file.
- By defining TEST_CMDLN_CPP you can compile the
- demo/test version of cmdln.cpp. Be sure you
- understand the demo/test code before using
- cmdln.cpp.
-
- */
-
- #include <string.h> /* strchr() */
- #include <cmdln.hpp>
-
- static char switches[] = "/-";
- /*
- Switches is initialized here for DOS switch
- characters. Change as necessary for your
- host OS shell.
- */
-
- void CmdLn::CmdLnReset(int argc, char *argv[],
- char *options)
- {
- this->argv = argv;
- this->options = options;
- opt = (char *) 0;
- this->argc = argc;
- optEnd = 0;
- optCh = optNot = '\0';
- optArg = (char *) 0;
- argi = 1;
- }
-
- int CmdLn::getOption(void)
- {
-
- char *lookup;
-
- optArg = (char *)0;
- if (optEnd) /* no more options allowed */
- return (optCh = 0);
- if (!opt || (*opt == '\0')) {
- if (argi >= argc) /* no more parameters */
- return (optEnd = optCh = -1);
- /* end of options */
- opt = argv[argi];
- /* next possible option cluster */
- if (!strchr(switches,*opt))
- /* Not an option cluster? */
- return (optEnd = optCh = -1);
- /* start non option parameters */
- argi++; /* next possible parameter */
- opt++; /* next possible option */
- if (!*opt || strchr(switches,*opt))
- /* Two switches or one by itself */
- return (optEnd = optCh = -1);
- /* means end of options */
- }
- if ((lookup = strchr(
- /* validate option character */
- options? options : "",
- optNot = *opt++))
- == (char *)0)
- return (optCh = '?');
- /* unknown option */
- if (lookup[1] == ':') {
- /* option takes argument */
- if (*opt != '\0')
- /* Is argument in this parameter? */
- optArg = opt;
- else if (argi < argc)
- /* Is argument in next parameter? */
- optArg = argv[argi++];
- opt = (char *) 0;
- /* no more options in this parameter */
- }
- return (optCh = *lookup);
- /* return option */
- }
-
- void CmdLn::nextCluster(void) { opt = (char *) 0; }
- /* start processing in next cluster */
-
- void CmdLn::lookForMoreOptions(void)
- {
- if (optEnd) {
- opt = (char *) 0;
- argi++;
- optEnd = 0;
- }
- }
-
-
- /*
- To use cmdln.cpp in your own programs be sure to
- comment out the following "#define TEST_CMDLN_CPP."
- */
- #define TEST_CMDLN_CPP
- #ifdef TEST_CMDLN_CPP
-
- #include <stdio.h>
-
- char *help[] = {
- "\nusage: cmdln -ooptions *",
- "\nwhere 'options' consists of the letters to "
- "look for, and",
- "\n '*' are the command line arguments to"
- " be parsed by 'options.'",
- "\n For the purposes of this test 'o' "
- "switches are skipped.",
- "\n\nFor example, with the command line: ",
- "\n\n cmdln /oC:af:z /afnew /zC cmdfile outfile",
- "\n\nthe 'options' string is 'C:af:z', which "
- "means that this particular invocation",
- "\nof the demo will recognize 'C', 'a', 'f' "
- "and 'z' as switch options. 'C' and",
- "\n'f' take arguments, which is indicated by"
- " the colon after each in the 'options'",
- "\nstring. Switch options are introduced by "
- "'/' or '-' in DOS. The 'options'",
- "\nstring is then used to parse the rest of "
- "the command line. In this case it",
- "\nrecognizes 'a', 'f' with argument 'new', "
- "'z', and 'C' with argument 'cmdfile.'",
- "\nRun this demo with command lines similar "
- "to this example to see how it",
- "\nworks. Then besure to read the notes in "
- "cmdln.cpp for complete instructions on",
- "\nhow to use the CmdLn class. The source "
- "code of this demo is also found in",
- "\ncmdln.cpp. Be sure to study how I coded "
- "the demo. You will then be ready to",
- "\nstart coding with the CmdLn class.\n",
- 0
- };
-
- main(int argc, char *argv[])
- {
- int i;
- CmdLn CL(argc,argv,"o:");
-
- (void) CL.getOption();
- if ((CL.optCh != 'o') || !CL.optArg) {
- for (i = 0; help[i]; i++)
- printf("%s",help[i]);
- return 1;
- }
- printf("\nTest the CmdLn class instance 'CL'");
- printf(" with the following command line:");
- printf("\n\n ");
- for (i = 0; i < argc; i++)
- printf("%s ",argv[i]);
- printf("\n\nParse for the following options: \n");
- for (i = 0; CL.optArg[i]; i++) {
- printf("\n %c",CL.optArg[i]);
- if (CL.optArg[i+1] == ':') {
- i++;
- printf(" with argument");
- }
- }
- printf("\n\nParameters parsed by 'CL' as ...\n");
-
- CL.CmdLnReset(argc, argv, CL.optArg);
- do {
- while (CL.getOption() != -1)
- if (CL.optCh == '?')
- if (CL.optNot == 'o')
- CL.nextCluster();
- else
- printf("\n CL.optNot: %c",CL.optNot);
- else {
- printf("\n CL.optCh: %c",CL.optCh);
- printf(" CL.optArg: %s",CL.optArg);
- }
- if (CL.Argi() < argc) {
- printf("\n CL.Argi(): %d",CL.Argi());
- printf(" argv[%d]: %s",
- CL.Argi(),argv[CL.Argi()]);
- }
- CL.lookForMoreOptions();
- } while (CL.Argi() < argc);
- printf("\n");
- return 0;
- }
-
- #endif