    Title:       Flexible Command Line Arguments Class
    Author:      Hector Santos
    Email:       codeproject@winserver.com
    Environment: VC++ 5.0-6.0, NT 4.0, Win95/98
    Keywords:    Command Line parameters, arguments, C/C++
    Level:       Intermediate
    Description: Class to handle command line parameters handling
    Section      MFC/C++
    SubSection   General

- Download source - 14 Kb

## Introduction

`CCommandLineParameters` is a C/C++ class to help you process command line arguments.

Yes, this is yet another "Command Line" processor. But in my opinion, the others I've seen don't have the flexibility or common usage standards often used command line tools switch options. `CCommandLineParameters` is designed to provide the following common/standard requirements:

- Implicit or explicit help option.
- Usage of both slash ("/") or dash ("-") switch characters
- Support to add more switch characters
- Switch case sensitivity support
- Switch abbreviation support
- Switch default value support
- First Non Switch Parameter support
- Support for Quoted parameters

## Nomenclature

The following legend is used to describe the `CCommandLineParameters` class:

> Command Line | The string passed to a program including the name of the current program.
> Parameter Line | The string passed to a program excluding the name of the current program.
> Arguments | The words in the parameter line each separated by space. Argument 1 is the first word, argument 2 is the same word, etc. Argument 0 is the name of the program. Please note that a double quote (") is used to combine multiple words are one argument. example: President "George Bush" The above is 2 arguments separate arguments, president and George Bush.
> Parameters | Same as arguments
> Switch | An argument or parameter which begins with a switch character. By default, the switch characters are dash ("-" or forward slash ("/")
> Abbreviated Switch | A switch that offers an abbreviation shortcut. Example: /s*end Allows for /send or /s to be used.
> Non-Switch | An argument or parameter which DOES NOT begin with a switch character.
> switch value | The value assigned to a switch.
> argument or parameter index | The index of the argument on the command line.

The following is standard command line syntax information which will be helpful to you when you wish to document or describe the possible command line parameters for your application in a help display:

> [] | When an parameter is surrounded with square brackets, this typically means the parameter is optional. The parameter is not required for normal operations of your program. example: program.exe [-p1]
> <> | When an parameter is surrounded with angle brackets, this typically means the parameter is required for normal operations of your program. example: program.exe <filename>
> | | The vertical bar means a choice between one parameter or parameter value is acceptable. example: program.exe </device:com1|com2>

For example, suppose an applications describes the following command line syntax:

> program.exe <p1> [-p2 <v2>] [[/p3 [v3]] [/p4]] [/p5 <v5|w5>]

By following the standard syntax, you can easily understand what are the required and optional parameters for any application.

In this example, p1 is a required parameter. The program will not run if it is not passed. The switches /p2, /p3, /p4 and /p5 are optional. If p2 is used, then v2 is required. If p3 is used, then V3 and /p4 are optional. However, the parameters v3 and /p4 are only valid if /p3 is used in the first place. If /P5 is used, the valid values are v5 or w5.

This basic syntax is standard across many platforms.

## Using the code

Using `CCommandLineParameters` is very simple. Simply instantiate or add an object like so to your source code:

>     CCommandLineParameters clp;

The constructor offer an option to pass the switch characters which are by default, "-/". If you wish to change the switch characters, you can do so by passing a string defining the characters to the constructor:

>     CCommandLineParameters clp("-/\\");  /* dash, forward and back slash*/

The basic and most common usage at this point is the Switch() function. It will cover 80% of your needs. All other member functions are based on the Switch() function to give you other capabilities.

Here is a fast "get started" example:

Suppose our program "sendfile.exe" has a command line syntax:

> sendfile.exe <filename> <-h*sot <hostname>> [-p*ort <port#>]

then the following code will satisfy the syntax:

>     void usage()
>     {
>       print("SendFile v1.0 Copyright (c) 2003 MyCompany.com\n");
>       print("usage: <filename> <-h*sot <hostname>> [-p*ort <port#>]\n");
>     }

>     void main()
>     {

>       CCommandLineParameters clp;

>       // check for ? or if no parameters are passed

>       if (clp.Help(TRUE)) {
>           usage();
>           return;
>       }

>       CString filename = clp.FirstNonSwitchStr();
>       CString hostname = clp.GetSwitchStr("h*ost");
>       DWORD deport = clp.GetSwitchInt("p*ort",80);

>       // Syntax checking for filename.
>       // First parameter must be a non-switch

>       if (clp.FirstNonSwitchIndex() != 1) {
>           print("! syntax error: filename required\n");
>           usage();
>           return;
>       }

>       // Syntax checking for host name.

>       if (hostname.IsEmpty()) {
>           print("! syntax error: no host defined\n");
>           usage();
>           return;
>       }

## Reference Guide

The following are the members of the `CCommandLineParameters` class.

`BOOL CheckHelp(const BOLO bNoSwitches = FALSE);`

Return TRUE if parameter #1 is "?", "/?" or "-?". If you want to return TRUE when no parameters are passed, then call CheckHelp(TRUE);

Example:

>     CCommandLineParameters clp;
>     if (clp.CheckHelp(TRUE)) {
>        ShowHelp();
>        exit(1);
>     }

`CString CommandLine();`

Return the entire command line as a string, including the current program name.

`CString ParamLine();`

Return the entire command line as a string, excluding the current program name.

`int ParamCount();`

Return the total number of parameters or arguments on the command line, including switches. This will always be a minimum of 1, which includes the parameter #0 the name of the current application.

`int SwitchCount();`

Return the total number of switch options on the command line.

`CString ParamStr(int index, const BOOL bGetAll = FALSE);`

Return the string at parameter #index. If bGetall is TRUE, then return the string starting at parameter #index.

Example:

program.exe -email user@domain.com -subject NewsLetter #22 March 2 1999

>     CCommandLineParameters clp;
>     CString email = clp.GetSwitchStr("-email");
>     CString Subject = "";
>     int i = clp.Switch("subject");
>     if (i > 0) Subject = clp.ParamStr(i+1,TRUE);

`int ParamInt(int index);`

Return the integer at parameter #index.

`int FirstNonSwitchIndex();`

Return the first parameter index where there the first non-switch parameter occurs.

`CString FirstNonSwitchStr();`

Return the string where there the first non-switch parameter occurs. See also `GetNonSwitchStr().`

`int Switch(const char *sz, const BOOL bCase = FALSE);`

Switch() will return the parameter index if the switch exist. Return 0 if not found.
The logic will allow for two types of switches:
/switch value
/switch:value
DO NOT PASS THE COLON. IT IS AUTOMATICALLY CHECKED. In other words, the following statements are the same:
Switch("server");
Switch("-server");
Switch("/server");
to handle the possible switch arguments and retrieval of switch values:
/server:value
/server value
-server:value
-server value

If you wish to have an abbreviation, insert a star "*" character in the switch at the position to indicate the number of abbreviated characters. If you wish to make it case sensitive, then pass bCase as TRUE.

Example:

>     // check for /st or /start switch (not case sensitive)
>     BOOL bStart =  clp.Switch("st*art");

`CString GetSwitchStr(const char *sz,
const char *szDefault = "",
const BOOL bCase = FALSE);`

`int GetSwitchInt(const char *sz,
const int iDefault = -1,
const BOOL bCase = FALSE);`

Return the string or integer for a given switch. Optionally pass the default value and if case sensitivity is to be used.

These functions support two types of switch inputs:

/switch:data
/switch data

Either format is acceptable.

`CString GetNonSwitchStr(const BOOL bBreakAtSwitch = TRUE,
const BOOL bFirstOnly = FALSE);`

Return the non switch string(s) depending on the values of bBreakAtSwitch and bFirstOnly.

> bBreakAtSwitch | bFirstOnly | Result
> TRUE | FALSE | Default Behavior, returns all strings non-switch strings starting at the first one found, stopping at the first switch found.
> TRUE | TRUE | returns the first non-switch string starting at the first one found.
> FALSE | TRUE | returns the first non-switch string.
> FALSE | FALSE | returns all the non-switch strings.

Examples:

program.exe file.txt -p:80 -H www.winserver.com
program.exe file.txt -p:80 -h 208.247.131.9

>     int port     = clp.GetSwitchInt("port",25,1);
>     CString host = clp.GetSwitchStr("HOST,"",1,TRUE);
>     CString ip   = clp.GetSwitchStr("host,"",1,TRUE);
>     CString file = clp.GetNonSwitchString(TRUE,TRUE);

In the above example, the switch for H is case sensitive. In one case (upper), it sets the host variable and in the the lower case option it sets the ip variable.

program.exe file1.txt file2.txt file2.txt -output out.txt

>     CString infiles = clp.GetNonSwitchString(TRUE,FALSE);
>     CString outfile = clp.GetSwitchStr("-output",1)

## Points of Interest

This class works under console and GUI applications. A maximum of 100 parameters are possible. A possible enhancement is a syntax validation parser. This would help reduce coding of valid parameter syntax.

## History

v1.0p March 5, 2003 - Initial Public Release

## About the Author

Hector Santos is the CTO of Santronics Software, Inc, developer of WINSERVER (Wildcat! Interactive Net Server), an integrated Dialup and Intranet Hosting Client/Server System. Hector made his mark in the early Off-line Mail Reader/Door days in the Fidonet Mail/File Network with the 1984 debut of the Silver Xpress OffLine Mail Door/Reader System. Before the internet, we connected with low speed modems and to read or create mail ONLINE was expensive. Silver Xpress and other similar products made it feasible for millions of people world wide to enjoy "BBSing" by downloading mail for offline reading and replying. In 1992 with the internet coming and online communications becoming more feasible, products like SX were beginning to die. Hector's next product was Platinum Xpress, a P2P like system (we just didn't call it P2P) for the automatic exchange of Mail and Files in a world wide network of Zones, Nets, Nodes and Points users. This was called FidoNet and believe it not, there is nothing in the market today to compares to the P2P technology found in FidoNet. In 1996, with the success of PX, Hector purchased the rights to a brand new product line called WINSERVER, a product way ahead of its time. WINSERVER is now Santronics's flag ship product line, and it is a leading provider for private intranet solutions, especially in the the Medical, Health and Claims/Collection Industry where mail and files needs to be exchanges in a Intranet manner using all kinds of connection devices, including direct connect modems which still to this day, is probably still the most secured way of transferring data without internet sniffing worries.