Last active
March 8, 2023 18:25
-
-
Save oscarkramer/e3de32126cb7a7edbf6a21c3bd824fa2 to your computer and use it in GitHub Desktop.
Long Option Parsing in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This gist is intended to be inserted into an application's main.cpp