Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

CmdLineParser.cc

Go to the documentation of this file.
00001 /*
00002  * CmdLineParser.cc
00003  *
00004  * Smalltalk like class library for C++
00005  * Command line arguments parser.
00006  *
00007  * Copyright (c) 2006 Milan Cermak
00008  */
00009 /*
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 #include <stlib/tools/CmdLineParser.h>
00025 #include <stlib/Callback.h>
00026 
00027 #include <stlib/tools/CmdLineMissingArgument.h>
00028 #include <stlib/tools/CmdLineUnknownArgument.h>
00029 #include <stlib/tools/CmdLineUnsufficientParams.h>
00030 
00031 #include <stlib/Array.h>
00032 #include <stlib/Character.h>
00033 #include <stlib/Iterator.h>
00034 #include <stlib/Object.h>
00035 #include <stlib/OrderedCollection.h>
00036 #include <stlib/String.h>
00037 #include <stlib/WriteStream.h>
00038 #include <stlib/POOBoundsError.h>
00039 
00040 #include <getopt.h>
00041 
00042 namespace Tools {
00043 
00044 class CommandLineArgument : public Core::Object
00045 {
00046   protected:
00047     String *long_argument;
00048     Character *short_argument;
00049     bool _mandatory;
00050     Callback<void> *_callback;
00051     Object *user_data;
00052     bool _evaluated;
00053 
00054   public:
00055     CommandLineArgument(String *longArg, Character *shortArg, bool mandatory,
00056                         Callback<void> *callback, Object *userData = nil)
00057     {
00058         long_argument = longArg;
00059         short_argument = shortArg;
00060         _mandatory = mandatory;
00061         _callback = callback;
00062         user_data = userData;
00063         _evaluated = false;
00064     }
00065 
00066     /* Printing protocol */
00067     virtual void printGetOptShortOn(Stream *stream)
00068     {
00069         if (short_argument == nil) return;
00070 
00071         stream->nextPut(short_argument);
00072         if (acceptsParameter())
00073             stream->nextPut(':');
00074     }
00075 
00076     /* Processing protocol */
00077     virtual void performCallback(void)
00078     {
00079         _callback->executeWith(user_data);
00080         _evaluated = true;
00081     }
00082 
00083     virtual void performCallbackWith(String *param)
00084     {
00085         _callback->executeWith(param);
00086         _evaluated = true;
00087     }
00088 
00089     /* Testing protocol */
00090     virtual bool acceptsParameter(void)
00091     {
00092         return _callback->argumentsNumber() > 0 && user_data == nil;
00093     }
00094 
00095     virtual bool matchShortArgument(int character)
00096     {
00097         return short_argument->isEqual((char) character);
00098     }
00099 
00100     virtual bool isMandatory(void)
00101     {
00102         return _mandatory;
00103     }
00104 
00105     virtual bool wasEvaluated(void)
00106     {
00107         return _evaluated;
00108     }
00109 
00110     /* Utilities protocol */
00111     virtual void fillGetOptLongOption(struct option *longopt)
00112     {
00113         longopt->name = long_argument->asCString();
00114         longopt->has_arg = acceptsParameter() ? 1 : 0;
00115         longopt->flag = NULL;
00116         if (short_argument == nil) longopt->val = 0;
00117         else
00118             longopt->val = short_argument->asInteger();
00119     }
00120 };
00121 
00122 /* Class-accessing protocol */
00123 CommandLineParser::CommandLineParser(void)
00124 {
00125     _arguments = new OrderedCollection;
00126     extra_argument_handler = nil;
00127     parameters_mandatory = false;
00128 }
00129 
00130 String *CommandLineParser::className(void) const
00131 {
00132     return new String("CommandLineParser");
00133 }
00134 
00135 /* Initialize protocol */
00136 void CommandLineParser::parametersMandatory(bool isMandatory)
00137 {
00138     parameters_mandatory = isMandatory;
00139 }
00140 
00141 /* Processing protocol */
00142 void CommandLineParser::process(int argc, char **argv)
00143 {
00144     int option_index = 0;
00145     char *shortOptions = collectShortOptions()->asCString();
00146     struct option *longOptions = collectLongOptions();
00147     CommandLineArgument *argument;
00148 
00149     optind = 0;     /* to force getopt start from beginning */
00150     while (1) {
00151         int c;
00152         c = getopt_long(argc, argv, shortOptions, longOptions, &option_index);
00153         if (c == -1) break;
00154 
00155         if (c == 0) {           /* long argument found */
00156             if (option_index >= _arguments->size()) {
00157                 (new CommandLineUnknownArgument(__PRETTY_FUNCTION__, new String(argv[optind-1])))
00158                     ->raiseFrom(this);
00159             }
00160             argument = dynamic_cast<CommandLineArgument *>(_arguments->at(option_index));
00161         } else {                /* short argument found */
00162             Iterator *i = _arguments->iterator();
00163             while (!i->finished()) {
00164                 argument = dynamic_cast<CommandLineArgument *>(i->value());
00165                 if (argument->matchShortArgument(c)) break;
00166                 i->next();
00167             }
00168             if (i->finished()) {  /* argument not found */
00169                 (new CommandLineUnknownArgument(__PRETTY_FUNCTION__, new String(argv[optind-1])))
00170                     ->raiseFrom(this);
00171             }
00172         }
00173 
00174         if (argument->acceptsParameter()) {
00175             argument->performCallbackWith(new String(optarg));
00176         } else {
00177             argument->performCallback();
00178         }
00179     }
00180 
00181     /* handle parameters */
00182     if (optind < argc) {
00183         if (extra_argument_handler != nil) {
00184             Array *extras = new Array(argc - optind);
00185             for (int i = 0; optind + i < argc; i++) {
00186                 extras->put(i, new String(argv[optind]));
00187             }
00188             extra_argument_handler->executeWith(extras);
00189         }
00190     } else if (parameters_mandatory) {
00191         (new CommandLineUnsufficientParameters(__PRETTY_FUNCTION__))
00192             ->raiseFrom(this);
00193     }
00194 
00195     checkMissingArguments();
00196 }
00197 
00198 /* Private protocol */
00199 void CommandLineParser::addArgument(String *longArg, Character *shortArg,
00200                                     bool mandatory, Callback<void> *callback,
00201                                     Object *userData)
00202 {
00203     CommandLineArgument *argument;
00204     argument = new CommandLineArgument(longArg, shortArg, mandatory,
00205                                        callback, userData);
00206     _arguments->add(argument);
00207 }
00208 
00209 String *CommandLineParser::collectShortOptions(void)
00210 {
00211     Iterator *i;
00212     Stream *stream;
00213     stream = (new String(2 * _arguments->size()))->writeStream();
00214 
00215     for (i = _arguments->iterator(); !i->finished(); i->next())
00216     {
00217         dynamic_cast<CommandLineArgument *>(i->value())->printGetOptShortOn(stream);
00218     }
00219     return dynamic_cast<String *>(stream->contents());
00220 }
00221 
00222 struct option *CommandLineParser::collectLongOptions(void)
00223 {
00224     struct option *longOptions;
00225     CommandLineArgument *argument;
00226     Iterator *i;
00227     int index;
00228 
00229     longOptions = (struct option *) GC_malloc((_arguments->size() + 1) * sizeof(struct option));
00230     for (i = _arguments->iterator(), index = 0; !i->finished(); i->next(), index++) {
00231         argument = dynamic_cast<CommandLineArgument *>(i->value());
00232         argument->fillGetOptLongOption(&longOptions[index]);
00233     }
00234     /* last item must by zero-filled */
00235     longOptions[index].name = NULL;
00236     longOptions[index].has_arg = 0;
00237     longOptions[index].flag = NULL;
00238     longOptions[index].val = 0;
00239     return longOptions;
00240 }
00241 
00242 void CommandLineParser::checkMissingArguments(void)
00243 {
00244     CommandLineArgument *argument;
00245     Iterator *i;
00246 
00247     for (i = _arguments->iterator(); !i->finished(); i->next()) {
00248         argument = dynamic_cast<CommandLineArgument *>(i->value());
00249         if (argument->isMandatory() && !argument->wasEvaluated()) {
00250             (new CommandLineMissingArgument(__PRETTY_FUNCTION__, argument))
00251                 ->raiseFrom(this);
00252         }
00253     }
00254 }
00255 
00256 }; /* namespace Tools */

Generated on Mon Nov 27 09:47:54 2006 for Smalltalk like C++ Class Library by  doxygen 1.4.2