The Lean Mean C++ Option Parser
src/example_arg.cc
Go to the documentation of this file.
00001 /* Written 2012 by Matthias S. Benkmann
00002  *
00003  * The author hereby waives all copyright and related rights to the contents
00004  * of this example file (example_arg.cc) to the extent possible under the law.
00005  */
00006 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include "optionparser.h"
00018 
00019 struct Arg: public option::Arg
00020 {
00021   static void printError(const char* msg1, const option::Option& opt, const char* msg2)
00022   {
00023     fprintf(stderr, "%s", msg1);
00024     fwrite(opt.name, opt.namelen, 1, stderr);
00025     fprintf(stderr, "%s", msg2);
00026   }
00027 
00028   static option::ArgStatus Unknown(const option::Option& option, bool msg)
00029   {
00030     if (msg) printError("Unknown option '", option, "'\n");
00031     return option::ARG_ILLEGAL;
00032   }
00033 
00034   static option::ArgStatus Required(const option::Option& option, bool msg)
00035   {
00036     if (option.arg != 0)
00037       return option::ARG_OK;
00038 
00039     if (msg) printError("Option '", option, "' requires an argument\n");
00040     return option::ARG_ILLEGAL;
00041   }
00042 
00043   static option::ArgStatus NonEmpty(const option::Option& option, bool msg)
00044   {
00045     if (option.arg != 0 && option.arg[0] != 0)
00046       return option::ARG_OK;
00047 
00048     if (msg) printError("Option '", option, "' requires a non-empty argument\n");
00049     return option::ARG_ILLEGAL;
00050   }
00051 
00052   static option::ArgStatus Numeric(const option::Option& option, bool msg)
00053   {
00054     char* endptr = 0;
00055     if (option.arg != 0 && strtol(option.arg, &endptr, 10)){};
00056     if (endptr != option.arg && *endptr == 0)
00057       return option::ARG_OK;
00058 
00059     if (msg) printError("Option '", option, "' requires a numeric argument\n");
00060     return option::ARG_ILLEGAL;
00061   }
00062 };
00063 
00064 enum  optionIndex { UNKNOWN, HELP, OPTIONAL, REQUIRED, NUMERIC, NONEMPTY };
00065 const option::Descriptor usage[] = {
00066 { UNKNOWN, 0,"", "",        Arg::Unknown, "USAGE: example_arg [options]\n\n"
00067                                           "Options:" },
00068 { HELP,    0,"", "help",    Arg::None,    "  \t--help  \tPrint usage and exit." },
00069 { OPTIONAL,0,"o","optional",Arg::Optional,"  -o[<arg>], \t--optional[=<arg>]"
00070                                           "  \tTakes an argument but is happy without one." },
00071 { REQUIRED,0,"r","required",Arg::Required,"  -r <arg>, \t--required=<arg>  \tMust have an argument." },
00072 { NUMERIC, 0,"n","numeric", Arg::Numeric, "  -n <num>, \t--numeric=<num>  \tRequires a number as argument." },
00073 { NONEMPTY,0,"1","nonempty",Arg::NonEmpty,"  -1 <arg>, \t--nonempty=<arg>"
00074                                           "  \tCan NOT take the empty string as argument." },
00075 { UNKNOWN, 0,"", "",        Arg::None,
00076  "\nExamples:\n"
00077  "  example_arg --unknown -o -n10 \n"
00078  "  example_arg -o -n10 file1 file2 \n"
00079  "  example_arg -nfoo file1 file2 \n"
00080  "  example_arg --optional -- file1 file2 \n"
00081  "  example_arg --optional file1 file2 \n"
00082  "  example_arg --optional=file1 file2 \n"
00083  "  example_arg --optional=  file1 file2 \n"
00084  "  example_arg -o file1 file2 \n"
00085  "  example_arg -ofile1 file2 \n"
00086  "  example_arg -unk file1 file2 \n"
00087  "  example_arg -r -- file1 \n"
00088  "  example_arg -r file1 \n"
00089  "  example_arg --required \n"
00090  "  example_arg --required=file1 \n"
00091  "  example_arg --nonempty= file1 \n"
00092  "  example_arg --nonempty=foo --numeric=999 --optional=bla file1 \n"
00093  "  example_arg -1foo \n"
00094  "  example_arg -1 -- \n"
00095  "  example_arg -1 \"\" \n"
00096 },
00097 { 0, 0, 0, 0, 0, 0 } };
00098 
00099 int main(int argc, char* argv[])
00100 {
00101   argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
00102   option::Stats stats(usage, argc, argv);
00103 
00104 #ifdef __GNUC__
00105     // GCC supports C99 VLAs for C++ with proper constructor calls.
00106   option::Option options[stats.options_max], buffer[stats.buffer_max];
00107 #else
00108     // use calloc() to allocate 0-initialized memory. It's not the same
00109     // as properly constructed elements, but good enough. Obviously in an
00110     // ordinary C++ program you'd use new[], but this file demonstrates that
00111     // TLMC++OP can be used without any dependency on the C++ standard library.
00112   option::Option* options = (option::Option*)calloc(stats.options_max, sizeof(option::Option));
00113   option::Option* buffer  = (option::Option*)calloc(stats.buffer_max,  sizeof(option::Option));
00114 #endif
00115 
00116   option::Parser parse(usage, argc, argv, options, buffer);
00117 
00118   if (parse.error())
00119     return 1;
00120 
00121   if (options[HELP] || argc == 0)
00122   {
00123     int columns = getenv("COLUMNS")? atoi(getenv("COLUMNS")) : 80;
00124     option::printUsage(fwrite, stdout, usage, columns);
00125     return 0;
00126   }
00127 
00128   for (int i = 0; i < parse.optionsCount(); ++i)
00129   {
00130     option::Option& opt = buffer[i];
00131     fprintf(stdout, "Argument #%d is ", i);
00132     switch (opt.index())
00133     {
00134       case HELP:
00135         // not possible, because handled further above and exits the program
00136       case OPTIONAL:
00137         if (opt.arg)
00138           fprintf(stdout, "--optional with optional argument '%s'\n", opt.arg);
00139         else
00140           fprintf(stdout, "--optional without the optional argument\n");
00141         break;
00142       case REQUIRED:
00143         fprintf(stdout, "--required with argument '%s'\n", opt.arg);
00144         break;
00145       case NUMERIC:
00146         fprintf(stdout, "--numeric with argument '%s'\n", opt.arg);
00147         break;
00148       case NONEMPTY:
00149         fprintf(stdout, "--nonempty with argument '%s'\n", opt.arg);
00150         break;
00151       case UNKNOWN:
00152         // not possible because Arg::Unknown returns ARG_ILLEGAL
00153         // which aborts the parse with an error
00154         break;
00155     }
00156   }
00157 
00158   for (int i = 0; i < parse.nonOptionsCount(); ++i)
00159     fprintf(stdout, "Non-option argument #%d is %s\n", i, parse.nonOption(i));
00160 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator