Skip to content

Instantly share code, notes, and snippets.

@oscarkramer
Last active March 8, 2023 18:25
Show Gist options
  • Save oscarkramer/e3de32126cb7a7edbf6a21c3bd824fa2 to your computer and use it in GitHub Desktop.
Save oscarkramer/e3de32126cb7a7edbf6a21c3bd824fa2 to your computer and use it in GitHub Desktop.
Long Option Parsing in C++
#include <getopt.h>
#include <iostream>
using namespace std;
void usage(const char* appName, int exitCode, string errMsg="")
{
if (!errMsg.empty())
cout<<"\n"<<errMsg<<endl;
cout<<"\nProgram description goes here..."
"\n"
"\nUsage: "<<appName<<" [options] <input-file>"
"\n"
"\nOptions:"
"\n -h Print this usage and exit."
"\n -o, --output-file <filename> Specify name of output file."
"\n --rational-value <float> Provide an optional double value."
"\n --version Output version information and exit."
"\n"
"\nExample: "<<appName<<" -o my-output.dat my-input.dat"
"\n"<<endl;
exit(exitCode);
}
int main (int argc, char **argv)
{
int c, versionFlag=0, optIndex=0;
double rationalValue=0.0;
string optName;
string inputFile, outputFile;
// Long options specified here as { <name>, <has-arg>, &<my-var>, <value> }, where:
// <name> long option name, e.g. "version"
// <has-arg> can be: no_argument | required_argument | optional_argument
// <my-var> int variable to be assigned to <value> if option present. If NULL, then nothing is
// assigned and it is up to the switch statement to read possible argument in optarg
// global variable. Alternatively, if NULL, and <value> set to the option's single
// character equivalent, getopt_long will behave as if the single character was
// specified. If <my-var> is used, variable must be pre-assigned to its default value.
// <value> If option present, value assigned to <my-var> if my-var is not null. Usually just
// a boolean 0 | 1. if <my-var> *is* null, then <value> can contain the single-char
// option and it will be returned as such by getopt_long.
static struct option long_options[] = {
{ "output-file", required_argument, 0, 'o' }, // filename found in optarg, parsed as 'o' option
{ "rational-value", required_argument, 0, 0 }, // value found in optarg
{ "version", no_argument, &versionFlag, 1 }, // versionFlag is set to 1
{ 0, 0, 0, 0} // always last
};
while ((c = getopt_long(argc, argv, "ho:", long_options, &optIndex)) != -1)
{
switch (c)
{
case 0:
// Indicates long option detected, use option index to access:
if (long_options[optIndex].flag != 0)
break; // value set in flag variable (e.g., versionFlag)
// Process long option that doesn't have a short option equivalent:
optName = long_options[optIndex].name;
if (optName == "rational-value")
rationalValue = atof(optarg);
break;
case 'h':
usage(argv[0], 0);
break;
case 'o':
outputFile = optarg;
break;
case '?':
// getopt_long already printed an error message.
usage(argv[0], 1);
break;
default:
usage(argv[0], 1, "Fatal parsing error occurred");
}
}
if (versionFlag)
{
cout<<"\nSoftware version 0.0.1\n"<<endl;
exit (0);
}
// Handle any remaining command line arguments (not options):
if (optind < argc)
inputFile = argv[optind++];
else
usage(argv[0], 1, "Input filename required.");
// Any additional items are superfluous:
if (optind < argc)
usage(argv[0], 1, "Extra command line arguments detected!");
// Proceed with application:
cout<<"inputFile: "<<inputFile<<endl;
cout<<"outputFile: "<<outputFile<<endl;
cout<<"rationalValue: "<<rationalValue<<endl;
exit (0);
}
@oscarkramer
Copy link
Author

This gist is intended to be inserted into an application's main.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment