summaryrefslogtreecommitdiff
path: root/cpp/src/IceUtil/Options.cpp
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2004-12-16 03:15:51 +0000
committerMichi Henning <michi@zeroc.com>2004-12-16 03:15:51 +0000
commitb5c3efca572afd6c9cadbc87e9f4c068d312d928 (patch)
treee34f481e7ed94f176fcbe266767fea241dc3c764 /cpp/src/IceUtil/Options.cpp
parentremove now returns null if the key is not found (diff)
downloadice-b5c3efca572afd6c9cadbc87e9f4c068d312d928.tar.bz2
ice-b5c3efca572afd6c9cadbc87e9f4c068d312d928.tar.xz
ice-b5c3efca572afd6c9cadbc87e9f4c068d312d928.zip
Changed command line parsing to use IceUtil::Options.
Diffstat (limited to 'cpp/src/IceUtil/Options.cpp')
-rwxr-xr-xcpp/src/IceUtil/Options.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/cpp/src/IceUtil/Options.cpp b/cpp/src/IceUtil/Options.cpp
new file mode 100755
index 00000000000..9e6c6396da7
--- /dev/null
+++ b/cpp/src/IceUtil/Options.cpp
@@ -0,0 +1,397 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2004 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/Options.h>
+#include <iostream>
+
+using namespace std;
+
+IceUtil::Options::Options()
+ : parseCalled(false)
+{
+}
+
+void
+IceUtil::Options::checkArgs(const string& shortOpt, const string& longOpt, bool needArg, const string& dflt)
+{
+ if(shortOpt.empty() && longOpt.empty())
+ {
+ throw APIError("short and long option cannot both be empty");
+ }
+
+ if(!shortOpt.empty())
+ {
+ if(shortOpt.size() != 1)
+ {
+ string err = "`";
+ err += shortOpt;
+ err += "': a short option cannot specify more than one option";
+ throw APIError(err);
+ }
+ if(shortOpt.find_first_of(" \t\n\r\f\v") != string::npos)
+ {
+ string err = "`";
+ err += shortOpt;
+ err += "': a short option cannot be whitespace";
+ throw APIError(err);
+ }
+ if(shortOpt[0] == '-')
+ {
+ string err = "`";
+ err += shortOpt;
+ err += "': a short option cannot be `-'";
+ throw APIError(err);
+ }
+ }
+
+ if(!longOpt.empty())
+ {
+ if(longOpt.find_first_of(" \t\n\r\f\v") != string::npos)
+ {
+ string err = "`";
+ err += longOpt;
+ err += "': a long option cannot contain whitespace";
+ throw APIError(err);
+ }
+ if(longOpt[0] == '-')
+ {
+ string err = "`";
+ err += longOpt;
+ err += "': a long option must not contain a leading `-'";
+ throw APIError(err);
+ }
+ }
+
+ if(!needArg && !dflt.empty())
+ {
+ throw APIError("a default value can be specified only for options requiring an argument");
+ }
+}
+
+void
+IceUtil::Options::addOpt(const string& shortOpt, const string& longOpt, ArgType at, string dflt, RepeatType rt)
+{
+ IceUtil::RecMutex::Lock sync(_m);
+
+ if(parseCalled)
+ {
+ throw APIError("cannot add options after parse() was called");
+ }
+
+ checkArgs(shortOpt, longOpt, at == NeedArg, dflt);
+
+ addValidOpt(shortOpt, ShortOpt, at, dflt, rt);
+ addValidOpt(longOpt, LongOpt, at, dflt, rt);
+}
+
+vector<string>
+IceUtil::Options::parse(int argc, char* argv[])
+{
+ IceUtil::RecMutex::Lock sync(_m);
+
+ if(parseCalled)
+ {
+ throw APIError("Cannot call parse() more than once on the same Option instance");
+ }
+ parseCalled = true;
+
+ int i;
+ for(i = 1; i < argc && *argv[i] == '-'; ++i)
+ {
+ if(argv[i][1] == '\0' || strcmp(argv[i], "--") == 0)
+ {
+ ++i;
+ break; // "-" and "--" indicate end of options.
+ }
+
+ string opt;
+ ValidOpts::iterator pos;
+ bool argDone = false;
+
+ if(argv[i][1] == '-')
+ {
+ //
+ // Long option. If the option has an argument, it can either be separated by '='
+ // or appear as a separate argument. For example, "--name value" is the same
+ // as "--name=value".
+ //
+ const char *p = argv[i] + 2;
+ while(*p != '=' && *p != '\0')
+ {
+ ++p;
+ }
+ if(*p == '=')
+ {
+ opt.assign(argv[i] + 2, p - argv[i] + 2);
+ }
+ else
+ {
+ opt = argv[i] + 2;
+ }
+
+ pos = checkOpt(opt, LongOpt);
+
+ if(*p == '=')
+ {
+ if(pos->second.arg == NoArg)
+ {
+ string err = "--";
+ err += opt;
+ err.push_back('=');
+ err += p + 1;
+ err += "': option does not take an argument";
+ throw BadOpt(err);
+ }
+ setOpt(opt, p + 1, pos->second.repeat);
+ argDone = true;
+ }
+ }
+ else
+ {
+ //
+ // Short option.
+ //
+ const char *p = argv[i];
+ char c;
+ while((c = *++p) != '\0')
+ {
+ opt.clear();
+ opt.push_back(c);
+ pos = checkOpt(opt, ShortOpt);
+ if(pos->second.arg == NeedArg && *(p + 1) != '\0')
+ {
+ string optarg;
+ while(*++p != '\0')
+ {
+ optarg.push_back(*p);
+ }
+ --p;
+ setOpt(opt, optarg, pos->second.repeat);
+ argDone = true;
+ }
+ }
+ }
+
+ if(!argDone)
+ {
+ if(pos->second.arg == NeedArg) // Need an argument that is separated by whitespace.
+ {
+ if(i == argc - 1)
+ {
+ string err = "`-";
+ if(opt.size() != 1)
+ {
+ err += "-";
+ }
+ err += opt;
+ err += "' option requires an argument";
+ throw BadOpt(err);
+ }
+ setOpt(opt, argv[++i], pos->second.repeat);
+ }
+ else
+ {
+ setOpt(opt, "1", pos->second.repeat);
+ }
+ }
+ }
+
+ vector<string> result;
+ while(i < argc)
+ {
+ result.push_back(argv[i++]);
+ }
+
+ return result;
+}
+
+bool
+IceUtil::Options::isSet(const string& opt) const
+{
+ IceUtil::RecMutex::Lock sync(_m);
+
+ if(!parseCalled)
+ {
+ throw APIError("cannot lookup options before calling parse()");
+ }
+
+ ValidOpts::const_iterator pos = checkOptIsValid(opt);
+ return pos->second.repeat == NoRepeat ? _opts.find(opt) != _opts.end() : _ropts.find(opt) != _ropts.end();
+}
+
+string
+IceUtil::Options::optArg(const string& opt) const
+{
+ IceUtil::RecMutex::Lock sync(_m);
+
+ if(!parseCalled)
+ {
+ throw APIError("cannot lookup options before calling parse()");
+ }
+
+ ValidOpts::const_iterator pos = checkOptHasArg(opt);
+
+ if(pos->second.repeat == Repeat)
+ {
+ string err = "`-";
+ if(pos->second.length == LongOpt)
+ {
+ err.push_back('-');
+ }
+ err += opt;
+ err += "': is a repeating option -- use argVec() to get its arguments";
+ throw APIError(err);
+ }
+
+ map<string, string>::const_iterator p = _opts.find(opt);
+ return p == _opts.end() ? "" : p->second;
+}
+
+vector<string>
+IceUtil::Options::argVec(const string& opt) const
+{
+ IceUtil::RecMutex::Lock sync(_m);
+
+ if(!parseCalled)
+ {
+ throw APIError("cannot lookup options before calling parse()");
+ }
+
+ ValidOpts::const_iterator pos = checkOptHasArg(opt);
+
+ if(pos->second.repeat == NoRepeat)
+ {
+ string err = "`-";
+ if(pos->second.length == LongOpt)
+ {
+ err.push_back('-');
+ }
+ err += opt + "': is a non-repeating option -- use optArg() to get its argument";
+ cerr << "p7" << endl;
+ throw APIError(err);
+ }
+
+ map<string, vector<string> >::const_iterator p = _ropts.find(opt);
+ return p == _ropts.end() ? vector<string>() : p->second;
+}
+
+void
+IceUtil::Options::addValidOpt(const string& opt, LengthType lt, ArgType at, const string& dflt, RepeatType rt)
+{
+ if(opt.empty())
+ {
+ return;
+ }
+
+ ValidOpts::iterator pos = _validOpts.find(opt);
+ if(pos != _validOpts.end())
+ {
+ string err = "`";
+ err += opt;
+ err += "': duplicate option";
+ throw APIError(err);
+ }
+
+ OptionDetails od;
+ od.length = lt;
+ od.arg = at;
+ od.repeat = rt;
+
+ _validOpts.insert(pos, make_pair(opt, od));
+
+ if(at == NeedArg && !dflt.empty())
+ {
+ setOpt(opt, dflt, rt);
+ }
+}
+
+IceUtil::Options::ValidOpts::iterator
+IceUtil::Options::checkOpt(const string& opt, LengthType lt)
+{
+ ValidOpts::iterator pos = _validOpts.find(opt);
+ if(pos == _validOpts.end())
+ {
+ string err = "invalid option: `-";
+ if(lt == LongOpt)
+ {
+ err.push_back('-');
+ }
+ err += opt;
+ err.push_back('\'');
+ throw BadOpt(err);
+ }
+
+ if(pos->second.repeat == NoRepeat && _opts.find(opt) != _opts.end())
+ {
+ string err = "`-";
+ if(lt == LongOpt)
+ {
+ err.push_back('-');
+ }
+ err += opt + ":' option cannot be repeated";
+ throw BadOpt(err);
+ }
+
+ return pos;
+}
+
+void
+IceUtil::Options::setOpt(const string& opt, const string& val, RepeatType rt)
+{
+ if(rt == Repeat)
+ {
+ ROpts::iterator pos = _ropts.find(opt);
+ if(pos != _ropts.end())
+ {
+ pos->second.push_back(val);
+ }
+ else
+ {
+ vector<string> vec;
+ vec.push_back(val);
+ _ropts.insert(pos, make_pair(opt, vec));
+ }
+ }
+ else
+ {
+ _opts[opt] = val;
+ }
+}
+
+IceUtil::Options::ValidOpts::const_iterator
+IceUtil::Options::checkOptIsValid(const string& opt) const
+{
+ ValidOpts::const_iterator pos = _validOpts.find(opt);
+ if(pos == _validOpts.end())
+ {
+ string err = "`";
+ err += opt;
+ err += "': invalid option";
+ throw APIError(err);
+ }
+ return pos;
+}
+
+IceUtil::Options::ValidOpts::const_iterator
+IceUtil::Options::checkOptHasArg(const string& opt) const
+{
+ ValidOpts::const_iterator pos = checkOptIsValid(opt);
+ if(pos->second.arg == NoArg)
+ {
+ string err = "`-";
+ if(pos->second.length == LongOpt)
+ {
+ err.push_back('-');
+ }
+ err += opt;
+ err += "': option does not take arguments";
+ throw APIError(err);
+ }
+ return pos;
+}