aboutsummaryrefslogtreecommitdiff
path: root/tools/iDSK/src/getopt_pp.cpp
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-11-05 11:22:55 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-11-05 11:31:28 +0000
commit2fbdf974338bde8576efdae40a819a76b2391033 (patch)
tree64d41a37470143f142344f9a439d96de3e7918c2 /tools/iDSK/src/getopt_pp.cpp
downloadkitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz
kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip
Initial import of the open source release
Diffstat (limited to 'tools/iDSK/src/getopt_pp.cpp')
-rw-r--r--tools/iDSK/src/getopt_pp.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/tools/iDSK/src/getopt_pp.cpp b/tools/iDSK/src/getopt_pp.cpp
new file mode 100644
index 0000000..a497c14
--- /dev/null
+++ b/tools/iDSK/src/getopt_pp.cpp
@@ -0,0 +1,269 @@
+/*
+GetOpt_pp: Yet another C++ version of getopt.
+ This file is part of GetOpt_pp.
+
+ Copyright (C) Daniel Gutson, FuDePAN 2007-2010
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt in the root directory or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+
+ GetOpt_pp IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <fstream>
+
+#if __APPLE__
+#include <crt_externs.h>
+#elif _WIN32
+#include <Stdio.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "getopt_pp.h"
+
+namespace GetOpt
+{
+
+GETOPT_INLINE Token* GetOpt_pp::_add_token(const std::string& value, Token::Type type)
+{
+ Token* const ret = new Token(value, type);
+ if (_first_token == NULL)
+ _first_token = ret;
+ else
+ _last_token->link_to(ret);
+ _last_token = ret;
+ return ret;
+}
+
+GETOPT_INLINE void GetOpt_pp::_init_flags()
+{
+ std::stringstream ss;
+ _flags = ss.flags();
+}
+
+GETOPT_INLINE void GetOpt_pp::_parse_sub_file(const std::string& file)
+{
+ std::ifstream ifile(file.c_str());
+ if (!ifile)
+ throw OptionsFileNotFoundEx(file);
+
+ std::vector<std::string> args;
+ std::string arg;
+
+ while (ifile >> arg)
+ args.push_back(arg);
+
+ _parse(args);
+}
+
+GETOPT_INLINE void GetOpt_pp::_parse(const std::vector<std::string>& args)
+{
+ bool any_option_processed = false;
+ const size_t argc = args.size();
+
+ size_t start = 0;
+ if ( _app_name.empty() )
+ {
+ _app_name = args[0];
+ start = 1;
+ }
+
+ // parse arguments by their '-' or '--':
+ // (this will be a state machine soon)
+ for (size_t i = start; i < argc; i++)
+ {
+ const std::string& currentArg = args[i];
+
+ if (currentArg[0] == '-' && currentArg.size() > 1)
+ {
+ // see what's next, differentiate whether it's short or long:
+ if (currentArg[1] == '-')
+ {
+ if ( currentArg.size() > 2 )
+ {
+ // long option
+ _longOps[currentArg.substr(2)].token = _add_token(currentArg.substr(2), Token::LongOption);
+ }
+ else
+ {
+ // it's the -- option alone
+ _longOps[currentArg].token = _add_token(currentArg, Token::GlobalArgument);
+ }
+
+ any_option_processed = true;
+ }
+ else
+ {
+ // check if it is a negative number: rules
+ // * floating point negative numbers are straight classified as 'arguments'
+ // * integer negative numbers of more than 1 digit length are also 'arguments'
+ // * integer negatives of 1 digit length can be either arguments or short options.
+ // * anything else: short options.
+ int anInt;
+ float aFloat;
+ std::stringstream dummy;
+ if ( convert(currentArg, anInt, dummy.flags()) == _Option::OK )
+ {
+ if ( currentArg.size() > 2 ) // if it's larger than -d (d=digit), then assume it's a negative number:
+ _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument);
+ else // size == 2: it's a 1 digit negative number
+ _shortOps[currentArg[1]].token = _add_token(currentArg, Token::PossibleNegativeArgument);
+ }
+ else if ( convert(currentArg, aFloat, dummy.flags()) == _Option::OK )
+ _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument);
+ else
+ {
+ // short option
+ // iterate over all of them, keeping the last one in currentData
+ // (so the intermediates will generate 'existent' arguments, as of '-abc')
+ for( size_t j = 1; j < currentArg.size(); j++ )
+ _shortOps[currentArg[j]].token = _add_token(std::string(currentArg, j, 1), Token::ShortOption);
+ }
+
+ any_option_processed = true;
+ }
+ }
+ else if ( currentArg[0] == '@' && currentArg.size() > 1 )
+ {
+ // suboptions file
+ _parse_sub_file(currentArg.substr(1));
+ }
+ else
+ {
+ _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument);
+ }
+ }
+
+ _last = _Option::OK; // TODO: IMPROVE!!
+}
+
+GETOPT_INLINE void GetOpt_pp::_argc_argv_to_vector(int argc, const char* const* const argv, std::vector<std::string>& args)
+{
+ for (int i = 0; i < argc; i++)
+ args.push_back(argv[i]);
+}
+
+GETOPT_INLINE GetOpt_pp::TokensDeleter::~TokensDeleter()
+{
+ Token* next;
+ Token* current(_first);
+ while (current != NULL)
+ {
+ next = current->next;
+ delete current;
+ current = next;
+ }
+}
+
+GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv)
+ : _exc(std::ios_base::goodbit), _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token)
+{
+ _init_flags();
+ std::vector<std::string> args;
+ _argc_argv_to_vector(argc, argv, args);
+ _parse(args);
+}
+
+GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv, _EnvTag)
+ : _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token)
+{
+ _init_flags();
+ std::vector<std::string> args;
+ _argc_argv_to_vector(argc, argv, args);
+ _parse(args);
+}
+
+GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (const _Option& opt)
+{
+ if (_last != _Option::ParsingError)
+ {
+ _last = opt(_shortOps, _longOps, _first_token, _flags);
+
+ switch (_last)
+ {
+ case _Option::OK:
+ break;
+
+ case _Option::OptionNotFound:
+ if (_exc & std::ios_base::eofbit)
+ throw OptionNotFoundEx();
+ break;
+
+ case _Option::BadType:
+ if (_exc & std::ios_base::failbit)
+ throw InvalidFormatEx();
+ break;
+
+ case _Option::NoArgs:
+ if (_exc & std::ios_base::eofbit)
+ throw ArgumentNotFoundEx();
+ break;
+
+ case _Option::TooManyArgs:
+ if (_exc & std::ios_base::failbit)
+ throw TooManyArgumentsEx();
+ break;
+
+ case _Option::OptionNotFound_NoEx:
+ break; // Ok, it will be read by casting to bool
+
+ case _Option::ParsingError:
+ break; // just to disable warning
+ }
+ }
+ else if (_exc & std::ios_base::failbit)
+ throw ParsingErrorEx();
+
+ return *this;
+}
+
+GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (std::ios_base & (*iomanip)(std::ios_base&))
+{
+ std::stringstream ss;
+ ss.flags(_flags);
+ _flags = (ss << iomanip).flags();
+ return *this;
+}
+
+GETOPT_INLINE bool GetOpt_pp::options_remain() const
+{
+ bool remain = false;
+ ShortOptions::const_iterator it = _shortOps.begin();
+ while (it != _shortOps.end() && !remain)
+ {
+ remain = (it->second.flags == OptionData::CmdLine_NotExtracted);
+ ++it;
+ }
+
+ if (!remain)
+ {
+ LongOptions::const_iterator it = _longOps.begin();
+ while (it != _longOps.end() && !remain)
+ {
+ remain = (it->second.flags == OptionData::CmdLine_NotExtracted);
+ ++it;
+ }
+ }
+
+ if (!remain)
+ {
+ // check for the global arguments:
+ Token* token = _first_token;
+ while (!remain && token != NULL)
+ {
+ remain = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet);
+ token = token->next;
+ }
+ }
+
+ return remain;
+}
+
+}