mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-03 11:00:14 -05:00
- added argstream to handle commandline arguments
- switched tests to use the common value of argstream in libretroshare, rather than the one in tests/common - reworked command line arguments in rsinit and retroshare-nogui. - improved passwd hash explanations - improved command-line help. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6559 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
9ffb625f9a
commit
aba5033604
@ -92,7 +92,7 @@ std::string pgp_pwd_callback(void * /*hook*/, const char *uid_hint, const char *
|
||||
fprintf(stderr, "pgp_pwd_callback() called.\n");
|
||||
#endif
|
||||
std::string password;
|
||||
rsicontrol->getNotify().askForPassword(uid_hint, prev_was_bad, password) ;
|
||||
rsicontrol->getNotify().askForPassword(std::string("Please enter your PGP password for key ")+uid_hint+" :", prev_was_bad, password) ;
|
||||
|
||||
return password ;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "util/rswin.h"
|
||||
#endif
|
||||
|
||||
#include "util/argstream.h"
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsrandom.h"
|
||||
@ -122,12 +123,11 @@ class RsInitConfig
|
||||
static bool forceExtPort;
|
||||
static bool forceLocalAddr;
|
||||
static unsigned short port;
|
||||
static char inet[256];
|
||||
static std::string inet ;
|
||||
|
||||
/* Logging */
|
||||
static bool haveLogFile;
|
||||
static bool outStderr;
|
||||
static bool haveDebugLevel;
|
||||
static int debugLevel;
|
||||
static std::string logfname;
|
||||
|
||||
@ -183,12 +183,11 @@ bool RsInitConfig::isWindowsXP = false;
|
||||
bool RsInitConfig::forceExtPort;
|
||||
bool RsInitConfig::forceLocalAddr;
|
||||
unsigned short RsInitConfig::port;
|
||||
char RsInitConfig::inet[256];
|
||||
std::string RsInitConfig::inet;
|
||||
|
||||
/* Logging */
|
||||
bool RsInitConfig::haveLogFile;
|
||||
bool RsInitConfig::outStderr;
|
||||
bool RsInitConfig::haveDebugLevel;
|
||||
int RsInitConfig::debugLevel;
|
||||
std::string RsInitConfig::logfname;
|
||||
|
||||
@ -220,12 +219,11 @@ void RsInit::InitRsConfig()
|
||||
RsInitConfig::outStderr = false;
|
||||
RsInitConfig::forceExtPort = false;
|
||||
|
||||
strcpy(RsInitConfig::inet, "127.0.0.1");
|
||||
RsInitConfig::inet = std::string("127.0.0.1");
|
||||
|
||||
RsInitConfig::autoLogin = false; // .
|
||||
RsInitConfig::startMinimised = false;
|
||||
RsInitConfig::passwd = "";
|
||||
RsInitConfig::haveDebugLevel = false;
|
||||
RsInitConfig::debugLevel = PQL_WARNING;
|
||||
RsInitConfig::udpListenerOnly = false;
|
||||
|
||||
@ -330,19 +328,12 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
||||
{
|
||||
|
||||
/* THIS IS A HACK TO ALLOW WINDOWS TO ACCEPT COMMANDLINE ARGUMENTS */
|
||||
|
||||
|
||||
|
||||
|
||||
int argc;
|
||||
int i;
|
||||
#ifdef USE_CMD_ARGS
|
||||
char** argv = argvIgnored;
|
||||
argc = argcIgnored;
|
||||
|
||||
|
||||
#else
|
||||
|
||||
const int MAX_ARGS = 32;
|
||||
int j;
|
||||
char *argv[MAX_ARGS];
|
||||
@ -368,24 +359,16 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
||||
}
|
||||
}
|
||||
argc = i;
|
||||
|
||||
#endif
|
||||
|
||||
for( i=0; i<argc; i++)
|
||||
{
|
||||
printf("%d: %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* for static PThreads under windows... we need to init the library...
|
||||
*/
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
pthread_win32_process_attach_np();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
@ -394,6 +377,41 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
||||
/* getopt info: every availiable option is listed here. if it is followed by a ':' it
|
||||
needs an argument. If it is followed by a '::' the argument is optional.
|
||||
*/
|
||||
//RsInitConfig::logfname = "" ;
|
||||
//RsInitConfig::inet = "" ;
|
||||
|
||||
argstream as(argc,argv) ;
|
||||
|
||||
as >> option('a',"auto-login" ,RsInitConfig::autoLogin ,"AutoLogin (Windows Only) + StartMinimised")
|
||||
>> option('m',"minimized" ,RsInitConfig::startMinimised ,"Start minimized." )
|
||||
>> option('s',"stderr" ,RsInitConfig::outStderr ,"output to stderr instead of log file." )
|
||||
>> option('u',"udp" ,RsInitConfig::udpListenerOnly,"Only listen to UDP." )
|
||||
>> option('e',"external-port" ,RsInitConfig::forceExtPort ,"Use a forwarded external port." )
|
||||
|
||||
>> parameter('l',"log-file" ,RsInitConfig::logfname ,"logfile" ,"Set Log filename." ,false)
|
||||
>> parameter('d',"debug-level" ,RsInitConfig::debugLevel ,"level" ,"Set debug level." ,false)
|
||||
>> parameter('w',"password" ,RsInitConfig::passwd ,"password" ,"Set Login Password." ,false)
|
||||
>> parameter('i',"ip-address" ,RsInitConfig::inet ,"nnn.nnn.nnn.nnn", "Set IP address to use." ,false)
|
||||
>> parameter('p',"port" ,RsInitConfig::port ,"port", "Set listenning port to use." ,false)
|
||||
>> parameter('c',"base-dir" ,RsInitConfig::basedir ,"directory", "Set base directory." ,false)
|
||||
>> parameter('U',"user-id" ,prefUserString ,"ID", "[User Name/GPG id/SSL id] Sets Account to Use, Useful when Autologin is enabled",false)
|
||||
>> parameter('r',"link" ,RsInitConfig::RetroShareLink ,"retroshare://...", "Use a given Retroshare Link" ,false)
|
||||
#ifdef LOCALNET_TESTING
|
||||
>> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false)
|
||||
#endif
|
||||
>> help() ;
|
||||
|
||||
as.defaultErrorHandling(true) ;
|
||||
|
||||
if(RsInitConfig::autoLogin) RsInitConfig::startMinimised = true ;
|
||||
if(RsInitConfig::outStderr) RsInitConfig::haveLogFile = false ;
|
||||
if(!RsInitConfig::logfname.empty()) RsInitConfig::haveLogFile = true;
|
||||
if(!RsInitConfig::inet.empty()) RsInitConfig::forceLocalAddr = true;
|
||||
#ifdef LOCALNET_TESTING
|
||||
if(!portRestrictions.empty()) doPortRestrictions = true;
|
||||
#endif
|
||||
|
||||
#ifdef SUSPENDED_CODE
|
||||
#ifdef LOCALNET_TESTING
|
||||
while((c = getopt(argc, argv,"hesamui:p:c:w:l:d:U:r:R:")) != -1)
|
||||
#else
|
||||
@ -402,85 +420,6 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
RsInitConfig::autoLogin = true;
|
||||
RsInitConfig::startMinimised = true;
|
||||
std::cerr << "AutoLogin Allowed / Start Minimised On";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'm':
|
||||
RsInitConfig::startMinimised = true;
|
||||
std::cerr << "Start Minimised On";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'l':
|
||||
RsInitConfig::logfname = optarg;
|
||||
std::cerr << "LogFile (" << RsInitConfig::logfname;
|
||||
std::cerr << ") Selected" << std::endl;
|
||||
RsInitConfig::haveLogFile = true;
|
||||
break;
|
||||
case 'w':
|
||||
RsInitConfig::passwd = optarg;
|
||||
std::cerr << "Password Specified(********" ; //<< RsInitConfig::passwd;
|
||||
std::cerr << ") Selected" << std::endl;
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(RsInitConfig::inet, optarg, 256);
|
||||
std::cerr << "New Inet Addr(" << RsInitConfig::inet;
|
||||
std::cerr << ") Selected" << std::endl;
|
||||
RsInitConfig::forceLocalAddr = true;
|
||||
break;
|
||||
case 'p':
|
||||
RsInitConfig::port = atoi(optarg);
|
||||
std::cerr << "New Listening Port(" << RsInitConfig::port;
|
||||
std::cerr << ") Selected" << std::endl;
|
||||
break;
|
||||
case 'c':
|
||||
RsInitConfig::basedir = optarg;
|
||||
std::cerr << "New Base Config Dir(";
|
||||
std::cerr << RsInitConfig::basedir;
|
||||
std::cerr << ") Selected" << std::endl;
|
||||
break;
|
||||
case 's':
|
||||
RsInitConfig::outStderr = true;
|
||||
RsInitConfig::haveLogFile = false;
|
||||
std::cerr << "Output to Stderr";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'd':
|
||||
RsInitConfig::haveDebugLevel = true;
|
||||
RsInitConfig::debugLevel = atoi(optarg);
|
||||
std::cerr << "Opt for new Debug Level";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'u':
|
||||
RsInitConfig::udpListenerOnly = true;
|
||||
std::cerr << "Opt for only udpListener";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'e':
|
||||
RsInitConfig::forceExtPort = true;
|
||||
std::cerr << "Opt for External Port Mode";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'U':
|
||||
prefUserString = optarg;
|
||||
std::cerr << "Opt for User Id ";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
case 'r':
|
||||
RsInitConfig::RetroShareLink = optarg;
|
||||
std::cerr << "Opt for RetroShare link";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
#ifdef LOCALNET_TESTING
|
||||
case 'R':
|
||||
portRestrictions = optarg;
|
||||
doPortRestrictions = true;
|
||||
std::cerr << "Opt for Port Restrictions";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
std::cerr << "Help: " << std::endl;
|
||||
std::cerr << "The commandline options are for retroshare-nogui, a headless server in a shell, or systems without QT." << std::endl << std::endl;
|
||||
@ -510,32 +449,31 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
setOutputLevel(RsInitConfig::debugLevel);
|
||||
|
||||
// set the default Debug Level...
|
||||
if (RsInitConfig::haveDebugLevel)
|
||||
{
|
||||
if ((RsInitConfig::debugLevel > 0) &&
|
||||
(RsInitConfig::debugLevel <= PQL_DEBUG_ALL))
|
||||
{
|
||||
std::cerr << "Setting Debug Level to: ";
|
||||
std::cerr << RsInitConfig::debugLevel;
|
||||
std::cerr << std::endl;
|
||||
setOutputLevel(RsInitConfig::debugLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Ignoring Invalid Debug Level: ";
|
||||
std::cerr << RsInitConfig::debugLevel;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
}
|
||||
// // set the default Debug Level...
|
||||
// if (RsInitConfig::haveDebugLevel)
|
||||
// {
|
||||
// if ((RsInitConfig::debugLevel > 0) &&
|
||||
// (RsInitConfig::debugLevel <= PQL_DEBUG_ALL))
|
||||
// {
|
||||
// std::cerr << "Setting Debug Level to: ";
|
||||
// std::cerr << RsInitConfig::debugLevel;
|
||||
// std::cerr << std::endl;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// std::cerr << "Ignoring Invalid Debug Level: ";
|
||||
// std::cerr << RsInitConfig::debugLevel;
|
||||
// std::cerr << std::endl;
|
||||
// }
|
||||
// }
|
||||
|
||||
// set the debug file.
|
||||
if (RsInitConfig::haveLogFile)
|
||||
{
|
||||
setDebugFile(RsInitConfig::logfname.c_str());
|
||||
}
|
||||
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
@ -2599,7 +2537,7 @@ int RsServer::StartupRetroShare()
|
||||
laddr.sin_port = htons(RsInitConfig::port);
|
||||
|
||||
// universal
|
||||
laddr.sin_addr.s_addr = inet_addr(RsInitConfig::inet);
|
||||
laddr.sin_addr.s_addr = inet_addr(RsInitConfig::inet.c_str());
|
||||
|
||||
mPeerMgr->setLocalAddress(ownId, laddr);
|
||||
}
|
||||
|
@ -1,814 +0,0 @@
|
||||
/* Copyright (C) 2004 Xavier Décoret <Xavier.Decoret@imag.fr>
|
||||
*
|
||||
* argsteam is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Foobar is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Foobar; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef ARGSTREAM_H
|
||||
#define ARGSTREAM_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
class argstream;
|
||||
|
||||
template<class T>
|
||||
class ValueHolder;
|
||||
|
||||
template <typename T>
|
||||
argstream& operator>> (argstream&, const ValueHolder<T>&);
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueHolder<T>
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T>
|
||||
class ValueHolder
|
||||
{
|
||||
public:
|
||||
ValueHolder(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(const char* l,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(char s,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
friend argstream& operator>><>(argstream& s,const ValueHolder<T>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
T* value_;
|
||||
T initialValue_;
|
||||
std::string description_;
|
||||
bool mandatory_;
|
||||
};
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,l,b,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,b,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(const char* l,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(l,b,desc,mandatory);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of OptionHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class OptionHolder
|
||||
{
|
||||
public:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
friend argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
inline std::string name() const;
|
||||
inline std::string description() const;
|
||||
protected:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc);
|
||||
friend OptionHolder help(char s='h',
|
||||
const char* l="help",
|
||||
const char* desc="Display this help");
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
bool* value_;
|
||||
std::string description_;
|
||||
};
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
help(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
{
|
||||
return OptionHolder(s,l,desc);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValuesHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T,class O>
|
||||
class ValuesHolder
|
||||
{
|
||||
public:
|
||||
ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len);
|
||||
template<class A,class B> friend argstream& operator>>(argstream& s,const ValuesHolder<A,B>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
typedef T value_type;
|
||||
private:
|
||||
mutable O value_;
|
||||
std::string description_;
|
||||
int len_;
|
||||
char letter_;
|
||||
};
|
||||
template<class T,class O>
|
||||
inline ValuesHolder<T,O>
|
||||
values(const O& o,
|
||||
const char* desc="",
|
||||
int len=-1)
|
||||
{
|
||||
return ValuesHolder<T,O>(o,desc,len);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueParser
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template <class T>
|
||||
class ValueParser
|
||||
{
|
||||
public:
|
||||
inline T operator()(const std::string& s) const
|
||||
{
|
||||
std::istringstream is(s);
|
||||
T t;
|
||||
is>>t;
|
||||
return t;
|
||||
}
|
||||
};
|
||||
// We need to specialize for string otherwise parsing of a value that
|
||||
// contains space (for example a string with space passed in quotes on the
|
||||
// command line) would parse only the first element of the value!!!
|
||||
template <>
|
||||
class ValueParser<std::string>
|
||||
{
|
||||
public:
|
||||
inline std::string operator()(const std::string& s) const
|
||||
{
|
||||
return s;
|
||||
}
|
||||
};
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of argstream
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class argstream
|
||||
{
|
||||
public:
|
||||
inline argstream(int argc,char** argv);
|
||||
inline argstream(const char* c);
|
||||
template<class T>
|
||||
friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
|
||||
friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
template<class T,class O>
|
||||
friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& v);
|
||||
|
||||
inline bool helpRequested() const;
|
||||
inline bool isOk() const;
|
||||
inline std::string errorLog() const;
|
||||
inline std::string usage() const;
|
||||
inline void defaultErrorHandling(bool ignoreUnused=false) const;
|
||||
static inline char uniqueLetter();
|
||||
protected:
|
||||
void parse(int argc,char** argv);
|
||||
private:
|
||||
typedef std::list<std::string>::iterator value_iterator;
|
||||
typedef std::pair<std::string,std::string> help_entry;
|
||||
std::string progName_;
|
||||
std::map<std::string,value_iterator> options_;
|
||||
std::list<std::string> values_;
|
||||
bool minusActive_;
|
||||
bool isOk_;
|
||||
std::deque<help_entry> argHelps_;
|
||||
std::string cmdLine_;
|
||||
std::deque<std::string> errors_;
|
||||
bool helpRequested_;
|
||||
};
|
||||
//************************************************************
|
||||
// Implementation of ValueHolder<T>
|
||||
//************************************************************
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
const char* l,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(const char* l,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: longName_(l),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty()) {
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::description() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<description_;
|
||||
if (mandatory_)
|
||||
{
|
||||
os<<"(mandatory)";
|
||||
}
|
||||
else
|
||||
{
|
||||
os<<"(default="<<initialValue_<<")";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of OptionHolder
|
||||
//************************************************************
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(NULL),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty())
|
||||
{
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of ValuesHolder<T,O>
|
||||
//************************************************************
|
||||
template<class T,class O>
|
||||
ValuesHolder<T,O>::ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len)
|
||||
: value_(o),
|
||||
description_(desc),
|
||||
len_(len)
|
||||
{
|
||||
letter_ = argstream::uniqueLetter();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<letter_<<"i";
|
||||
return os.str();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of argstream
|
||||
//************************************************************
|
||||
inline
|
||||
argstream::argstream(int argc,char** argv)
|
||||
: progName_(argv[0]),
|
||||
minusActive_(true),
|
||||
isOk_(true)
|
||||
{
|
||||
parse(argc,argv);
|
||||
}
|
||||
inline
|
||||
argstream::argstream(const char* c)
|
||||
: progName_(""),
|
||||
minusActive_(true),
|
||||
isOk_(true)
|
||||
{
|
||||
std::string s(c);
|
||||
// Build argc, argv from s. We must add a dummy first element for
|
||||
// progName because parse() expects it!!
|
||||
std::deque<std::string> args;
|
||||
args.push_back("");
|
||||
std::istringstream is(s);
|
||||
while (is.good())
|
||||
{
|
||||
std::string t;
|
||||
is>>t;
|
||||
args.push_back(t);
|
||||
}
|
||||
char* pargs[args.size()];
|
||||
char** p = pargs;
|
||||
for (std::deque<std::string>::const_iterator
|
||||
iter = args.begin();
|
||||
iter != args.end();++iter)
|
||||
{
|
||||
*p++ = const_cast<char*>(iter->c_str());
|
||||
}
|
||||
parse(args.size(),pargs);
|
||||
}
|
||||
inline void
|
||||
argstream::parse(int argc,char** argv)
|
||||
{
|
||||
// Run thru all arguments.
|
||||
// * it has -- in front : it is a long name option, if remainder is empty,
|
||||
// it is an error
|
||||
// * it has - in front : it is a sequence of short name options, if
|
||||
// remainder is empty, deactivates option (- will
|
||||
// now be considered a char).
|
||||
// * if any other char, or if option was deactivated
|
||||
// : it is a value. Values are split in parameters
|
||||
// (immediately follow an option) and pure values.
|
||||
// Each time a value is parsed, if the previously parsed argument was an
|
||||
// option, then the option is linked to the value in case of it is a
|
||||
// option with parameter. The subtle point is that when several options
|
||||
// are given with short names (ex: -abc equivalent to -a -b -c), the last
|
||||
// parsed option is -c).
|
||||
// Since we use map for option, any successive call overides the previous
|
||||
// one: foo -a -b -a hello is equivalent to foo -b -a hello
|
||||
// For values it is not true since we might have several times the same
|
||||
// value.
|
||||
value_iterator* lastOption = NULL;
|
||||
for (char** a = argv,**astop=a+argc;++a!=astop;)
|
||||
{
|
||||
std::string s(*a);
|
||||
if (minusActive_ && s[0] == '-')
|
||||
{
|
||||
if (s.size() > 1 && s[1] == '-')
|
||||
{
|
||||
if (s.size() == 2)
|
||||
{
|
||||
minusActive_ = false;
|
||||
continue;
|
||||
}
|
||||
lastOption = &(options_[s.substr(2)] = values_.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.size() > 1)
|
||||
{
|
||||
// Parse all chars, if it is a minus we have an error
|
||||
for (std::string::const_iterator cter = s.begin();
|
||||
++cter != s.end();)
|
||||
{
|
||||
if (*cter == '-')
|
||||
{
|
||||
isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"- in the middle of a switch "<<a;
|
||||
errors_.push_back(os.str());
|
||||
break;
|
||||
}
|
||||
lastOption = &(options_[std::string(1,*cter)] = values_.end());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isOk_ = false;
|
||||
errors_.push_back("Invalid argument -");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values_.push_back(s);
|
||||
if (lastOption != NULL)
|
||||
{
|
||||
*lastOption = --values_.end();
|
||||
}
|
||||
lastOption = NULL;
|
||||
}
|
||||
}
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
for (std::map<std::string,value_iterator>::const_iterator
|
||||
iter = options_.begin();iter != options_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: option "<<iter->first;
|
||||
if (iter->second != values_.end())
|
||||
{
|
||||
std::cout<<" -> "<<*(iter->second);
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
for (std::list<std::string>::const_iterator
|
||||
iter = values_.begin();iter != values_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: value "<<*iter<<std::endl;
|
||||
}
|
||||
#endif // ARGSTREAM_DEBUG
|
||||
}
|
||||
inline bool
|
||||
argstream::isOk() const
|
||||
{
|
||||
return isOk_;
|
||||
}
|
||||
inline bool
|
||||
argstream::helpRequested() const
|
||||
{
|
||||
return helpRequested_;
|
||||
}
|
||||
inline std::string
|
||||
argstream::usage() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<"usage: "<<progName_<<cmdLine_<<'\n';
|
||||
unsigned int lmax = 0;
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
if (lmax<iter->first.size()) lmax = iter->first.size();
|
||||
}
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
|
||||
<<" : "<<iter->second<<'\n';
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
argstream::errorLog() const
|
||||
{
|
||||
std::string s;
|
||||
for(std::deque<std::string>::const_iterator iter = errors_.begin();
|
||||
iter != errors_.end();++iter)
|
||||
{
|
||||
s += *iter;
|
||||
s += '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline char
|
||||
argstream::uniqueLetter()
|
||||
{
|
||||
static unsigned int c = 'a';
|
||||
return c++;
|
||||
}
|
||||
template<class T>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValueHolder<T>& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
if (v.mandatory_)
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " -";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " --";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " value";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " [-";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " [--";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " value]";
|
||||
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line, either it
|
||||
// has an associated value in which case we assign it, or it has not, in
|
||||
// which case we have an error.
|
||||
if (iter->second != s.values_.end())
|
||||
{
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: found value "<<*(iter->second)<<std::endl;
|
||||
#endif
|
||||
ValueParser<T> p;
|
||||
*(v.value_) = p(*(iter->second));
|
||||
// The option and its associated value are removed, the subtle thing
|
||||
// is that someother options might have this associated value too,
|
||||
// which we must invalidate.
|
||||
s.values_.erase(iter->second);
|
||||
for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
{
|
||||
if (jter->second == iter->second)
|
||||
{
|
||||
jter->second = s.values_.end();
|
||||
}
|
||||
}
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"No value following switch "<<iter->first
|
||||
<<" on command line";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.mandatory_)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Mandatory parameter ";
|
||||
if (!v.shortName_.empty()) os<<'-'<<v.shortName_;
|
||||
if (!v.longName_.empty())
|
||||
{
|
||||
if (!v.shortName_.empty()) os<<'/';
|
||||
os<<"--"<<v.longName_;
|
||||
}
|
||||
os<<" missing";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline argstream&
|
||||
operator>>(argstream& s,const OptionHolder& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::string c;
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
c += " [-";
|
||||
c += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
c += " [--";
|
||||
c += v.longName_;
|
||||
}
|
||||
c += "]";
|
||||
s.cmdLine_ = c+s.cmdLine_;
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line then the
|
||||
// option is true and if an associated value was found, it is ignored
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = true;
|
||||
}
|
||||
// The option only is removed
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = false;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<class T,class O>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValuesHolder<T,O>& v)
|
||||
{
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<' '<<v.letter_<<'1';
|
||||
switch (v.len_)
|
||||
{
|
||||
case -1:
|
||||
os<<"...";
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
os<<"..."<<v.letter_<<v.len_;
|
||||
break;
|
||||
}
|
||||
s.cmdLine_ += os.str();
|
||||
}
|
||||
std::list<std::string>::iterator first = s.values_.begin();
|
||||
// We add to the iterator as much values as we can, limited to the length
|
||||
// specified (if different of -1)
|
||||
int n = v.len_ != -1?v.len_:s.values_.size();
|
||||
while (first != s.values_.end() && n-->0)
|
||||
{
|
||||
// Read the value from the string *first
|
||||
ValueParser<T> p;
|
||||
*(v.value_++) = p(*first );
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
// The value we just removed was maybe "remembered" by an option so we
|
||||
// remove it now.
|
||||
for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
{
|
||||
if (jter->second == first)
|
||||
{
|
||||
jter->second = s.values_.end();
|
||||
}
|
||||
}
|
||||
++first;
|
||||
}
|
||||
// Check if we have enough values
|
||||
if (n != 0)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Expecting "<<v.len_<<" values";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
// Erase the values parsed
|
||||
s.values_.erase(s.values_.begin(),first);
|
||||
return s;
|
||||
}
|
||||
inline void
|
||||
argstream::defaultErrorHandling(bool ignoreUnused) const
|
||||
{
|
||||
if (helpRequested_)
|
||||
{
|
||||
std::cout<<usage();
|
||||
exit(1);
|
||||
}
|
||||
if (!isOk_)
|
||||
{
|
||||
std::cerr<<errorLog();
|
||||
exit(1);
|
||||
}
|
||||
if (!ignoreUnused &&
|
||||
(!values_.empty() || !options_.empty()))
|
||||
{
|
||||
std::cerr<<"Unused arguments"<<std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // ARGSTREAM_H
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "util/rsdir.h"
|
||||
#include "util/utest.h"
|
||||
#include <common/testutils.h>
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
|
||||
INITTEST() ;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <util/utest.h>
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
//#include <pqi/cleanupxpgp.h>
|
||||
#include <retroshare/rspeers.h>
|
||||
#include <pgp/rscertificate.h>
|
||||
|
@ -11,7 +11,7 @@ extern "C"
|
||||
}
|
||||
|
||||
#include <util/utest.h>
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
|
||||
INITTEST() ;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <pgp/pgphandler.h>
|
||||
#include <util/utest.h>
|
||||
#include <util/rsdir.h>
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
|
||||
INITTEST() ;
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include "util/rsaes.h"
|
||||
#include "util/utest.h"
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include "util/rsdir.h"
|
||||
#include "util/utest.h"
|
||||
#include <common/argstream.h>
|
||||
#include <util/argstream.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
839
libretroshare/src/util/argstream.h
Normal file
839
libretroshare/src/util/argstream.h
Normal file
@ -0,0 +1,839 @@
|
||||
/* Copyright (C) 2004 Xavier Décoret <Xavier.Decoret@imag.fr>
|
||||
*
|
||||
* argsteam is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Foobar is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Foobar; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef ARGSTREAM_H
|
||||
#define ARGSTREAM_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
class argstream;
|
||||
|
||||
template<class T>
|
||||
class ValueHolder;
|
||||
|
||||
template <typename T>
|
||||
argstream& operator>> (argstream&, const ValueHolder<T>&);
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueHolder<T>
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T>
|
||||
class ValueHolder
|
||||
{
|
||||
public:
|
||||
ValueHolder(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char *valueName,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(const char* l,
|
||||
T& b,
|
||||
const char *valueName,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(char s,
|
||||
T& b,
|
||||
const char *valueName,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
friend argstream& operator>><>(argstream& s,const ValueHolder<T>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
std::string valueName_;
|
||||
T* value_;
|
||||
T initialValue_;
|
||||
std::string description_;
|
||||
bool mandatory_;
|
||||
};
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,l,b,"value",desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* valueName="value",
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,l,b,valueName,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
T& b,
|
||||
const char* valueName="value",
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,b,valueName,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(const char* l,
|
||||
T& b,
|
||||
const char* valueName="value",
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(l,b,desc,mandatory);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of OptionHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class OptionHolder
|
||||
{
|
||||
public:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
friend argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
inline std::string name() const;
|
||||
inline std::string description() const;
|
||||
protected:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc);
|
||||
friend OptionHolder help(char s='h',
|
||||
const char* l="help",
|
||||
const char* desc="Display this help");
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
bool* value_;
|
||||
std::string description_;
|
||||
};
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
help(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
{
|
||||
return OptionHolder(s,l,desc);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValuesHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T,class O>
|
||||
class ValuesHolder
|
||||
{
|
||||
public:
|
||||
ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len);
|
||||
template<class A,class B> friend argstream& operator>>(argstream& s,const ValuesHolder<A,B>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
typedef T value_type;
|
||||
private:
|
||||
mutable O value_;
|
||||
std::string description_;
|
||||
int len_;
|
||||
char letter_;
|
||||
};
|
||||
template<class T,class O>
|
||||
inline ValuesHolder<T,O>
|
||||
values(const O& o,
|
||||
const char* desc="",
|
||||
int len=-1)
|
||||
{
|
||||
return ValuesHolder<T,O>(o,desc,len);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueParser
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template <class T>
|
||||
class ValueParser
|
||||
{
|
||||
public:
|
||||
inline T operator()(const std::string& s) const
|
||||
{
|
||||
std::istringstream is(s);
|
||||
T t;
|
||||
is>>t;
|
||||
return t;
|
||||
}
|
||||
};
|
||||
// We need to specialize for string otherwise parsing of a value that
|
||||
// contains space (for example a string with space passed in quotes on the
|
||||
// command line) would parse only the first element of the value!!!
|
||||
template <>
|
||||
class ValueParser<std::string>
|
||||
{
|
||||
public:
|
||||
inline std::string operator()(const std::string& s) const
|
||||
{
|
||||
return s;
|
||||
}
|
||||
};
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of argstream
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class argstream
|
||||
{
|
||||
public:
|
||||
inline argstream(int argc,char** argv);
|
||||
inline argstream(const char* c);
|
||||
template<class T>
|
||||
friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
|
||||
friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
template<class T,class O>
|
||||
friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& v);
|
||||
|
||||
inline bool helpRequested() const;
|
||||
inline bool isOk() const;
|
||||
inline std::string errorLog() const;
|
||||
inline std::string usage() const;
|
||||
inline bool defaultErrorHandling(bool ignoreUnused=false) const;
|
||||
static inline char uniqueLetter();
|
||||
protected:
|
||||
void parse(int argc,char** argv);
|
||||
private:
|
||||
typedef std::list<std::string>::iterator value_iterator;
|
||||
typedef std::pair<std::string,std::string> help_entry;
|
||||
std::string progName_;
|
||||
std::map<std::string,value_iterator> options_;
|
||||
std::list<std::string> values_;
|
||||
bool minusActive_;
|
||||
bool isOk_;
|
||||
std::deque<help_entry> argHelps_;
|
||||
std::string cmdLine_;
|
||||
std::deque<std::string> errors_;
|
||||
bool helpRequested_;
|
||||
};
|
||||
//************************************************************
|
||||
// Implementation of ValueHolder<T>
|
||||
//************************************************************
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
const char* l,
|
||||
T& v,
|
||||
const char* valueName,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
valueName_(valueName),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(const char* l,
|
||||
T& v,
|
||||
const char* valueName,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: longName_(l),
|
||||
value_(&v),
|
||||
valueName_(valueName),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
T& v,
|
||||
const char* valueName,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
valueName_(valueName),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty()) {
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::description() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<description_;
|
||||
if (mandatory_)
|
||||
{
|
||||
os<<"(mandatory)";
|
||||
}
|
||||
else
|
||||
{
|
||||
os<<"(default="<<initialValue_<<")";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of OptionHolder
|
||||
//************************************************************
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(NULL),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty())
|
||||
{
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of ValuesHolder<T,O>
|
||||
//************************************************************
|
||||
template<class T,class O>
|
||||
ValuesHolder<T,O>::ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len)
|
||||
: value_(o),
|
||||
description_(desc),
|
||||
len_(len)
|
||||
{
|
||||
letter_ = argstream::uniqueLetter();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<letter_<<"i";
|
||||
return os.str();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of argstream
|
||||
//************************************************************
|
||||
inline
|
||||
argstream::argstream(int argc,char** argv)
|
||||
: progName_(argv[0]),
|
||||
minusActive_(true),
|
||||
isOk_(true),
|
||||
helpRequested_(false)
|
||||
{
|
||||
parse(argc,argv);
|
||||
}
|
||||
inline
|
||||
argstream::argstream(const char* c)
|
||||
: progName_(""),
|
||||
minusActive_(true),
|
||||
isOk_(true)
|
||||
{
|
||||
std::string s(c);
|
||||
// Build argc, argv from s. We must add a dummy first element for
|
||||
// progName because parse() expects it!!
|
||||
std::deque<std::string> args;
|
||||
args.push_back("");
|
||||
std::istringstream is(s);
|
||||
while (is.good())
|
||||
{
|
||||
std::string t;
|
||||
is>>t;
|
||||
args.push_back(t);
|
||||
}
|
||||
char* pargs[args.size()];
|
||||
char** p = pargs;
|
||||
for (std::deque<std::string>::const_iterator
|
||||
iter = args.begin();
|
||||
iter != args.end();++iter)
|
||||
{
|
||||
*p++ = const_cast<char*>(iter->c_str());
|
||||
}
|
||||
parse(args.size(),pargs);
|
||||
}
|
||||
inline void
|
||||
argstream::parse(int argc,char** argv)
|
||||
{
|
||||
// Run thru all arguments.
|
||||
// * it has -- in front : it is a long name option, if remainder is empty,
|
||||
// it is an error
|
||||
// * it has - in front : it is a sequence of short name options, if
|
||||
// remainder is empty, deactivates option (- will
|
||||
// now be considered a char).
|
||||
// * if any other char, or if option was deactivated
|
||||
// : it is a value. Values are split in parameters
|
||||
// (immediately follow an option) and pure values.
|
||||
// Each time a value is parsed, if the previously parsed argument was an
|
||||
// option, then the option is linked to the value in case of it is a
|
||||
// option with parameter. The subtle point is that when several options
|
||||
// are given with short names (ex: -abc equivalent to -a -b -c), the last
|
||||
// parsed option is -c).
|
||||
// Since we use map for option, any successive call overides the previous
|
||||
// one: foo -a -b -a hello is equivalent to foo -b -a hello
|
||||
// For values it is not true since we might have several times the same
|
||||
// value.
|
||||
value_iterator* lastOption = NULL;
|
||||
for (char** a = argv,**astop=a+argc;++a!=astop;)
|
||||
{
|
||||
std::string s(*a);
|
||||
if (minusActive_ && s[0] == '-')
|
||||
{
|
||||
if (s.size() > 1 && s[1] == '-')
|
||||
{
|
||||
if (s.size() == 2)
|
||||
{
|
||||
minusActive_ = false;
|
||||
continue;
|
||||
}
|
||||
lastOption = &(options_[s.substr(2)] = values_.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.size() > 1)
|
||||
{
|
||||
// Parse all chars, if it is a minus we have an error
|
||||
for (std::string::const_iterator cter = s.begin();
|
||||
++cter != s.end();)
|
||||
{
|
||||
if (*cter == '-')
|
||||
{
|
||||
isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"- in the middle of a switch "<<a;
|
||||
errors_.push_back(os.str());
|
||||
break;
|
||||
}
|
||||
lastOption = &(options_[std::string(1,*cter)] = values_.end());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isOk_ = false;
|
||||
errors_.push_back("Invalid argument -");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values_.push_back(s);
|
||||
if (lastOption != NULL)
|
||||
{
|
||||
*lastOption = --values_.end();
|
||||
}
|
||||
lastOption = NULL;
|
||||
}
|
||||
}
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
for (std::map<std::string,value_iterator>::const_iterator
|
||||
iter = options_.begin();iter != options_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: option "<<iter->first;
|
||||
if (iter->second != values_.end())
|
||||
{
|
||||
std::cout<<" -> "<<*(iter->second);
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
for (std::list<std::string>::const_iterator
|
||||
iter = values_.begin();iter != values_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: value "<<*iter<<std::endl;
|
||||
}
|
||||
#endif // ARGSTREAM_DEBUG
|
||||
}
|
||||
inline bool
|
||||
argstream::isOk() const
|
||||
{
|
||||
return isOk_;
|
||||
}
|
||||
inline bool
|
||||
argstream::helpRequested() const
|
||||
{
|
||||
return helpRequested_;
|
||||
}
|
||||
inline std::string
|
||||
argstream::usage() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<"usage: "<<progName_<<cmdLine_<<'\n';
|
||||
unsigned int lmax = 0;
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
if (lmax<iter->first.size()) lmax = iter->first.size();
|
||||
}
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
|
||||
<<" : "<<iter->second<<'\n';
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
argstream::errorLog() const
|
||||
{
|
||||
std::string s;
|
||||
for(std::deque<std::string>::const_iterator iter = errors_.begin();
|
||||
iter != errors_.end();++iter)
|
||||
{
|
||||
s += *iter;
|
||||
s += '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline char
|
||||
argstream::uniqueLetter()
|
||||
{
|
||||
static unsigned int c = 'a';
|
||||
return c++;
|
||||
}
|
||||
template<class T>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValueHolder<T>& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
if (v.mandatory_)
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " -";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " --";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " " + v.valueName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " [-";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " [--";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " " + v.valueName_ +"]";
|
||||
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line, either it
|
||||
// has an associated value in which case we assign it, or it has not, in
|
||||
// which case we have an error.
|
||||
if (iter->second != s.values_.end())
|
||||
{
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: found value "<<*(iter->second)<<std::endl;
|
||||
#endif
|
||||
ValueParser<T> p;
|
||||
*(v.value_) = p(*(iter->second));
|
||||
// The option and its associated value are removed, the subtle thing
|
||||
// is that someother options might have this associated value too,
|
||||
// which we must invalidate.
|
||||
s.values_.erase(iter->second);
|
||||
for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
{
|
||||
if (jter->second == iter->second)
|
||||
{
|
||||
jter->second = s.values_.end();
|
||||
}
|
||||
}
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"No value following switch "<<iter->first
|
||||
<<" on command line";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.mandatory_)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Mandatory parameter ";
|
||||
if (!v.shortName_.empty()) os<<'-'<<v.shortName_;
|
||||
if (!v.longName_.empty())
|
||||
{
|
||||
if (!v.shortName_.empty()) os<<'/';
|
||||
os<<"--"<<v.longName_;
|
||||
}
|
||||
os<<" missing";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline argstream&
|
||||
operator>>(argstream& s,const OptionHolder& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::string c;
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
c += " [-";
|
||||
c += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
c += " [--";
|
||||
c += v.longName_;
|
||||
}
|
||||
c += "]";
|
||||
s.cmdLine_ = c+s.cmdLine_;
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line then the
|
||||
// option is true and if an associated value was found, it is ignored
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = true;
|
||||
}
|
||||
// The option only is removed
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = false;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<class T,class O>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValuesHolder<T,O>& v)
|
||||
{
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<' '<<v.letter_<<'1';
|
||||
switch (v.len_)
|
||||
{
|
||||
case -1:
|
||||
os<<"...";
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
os<<"..."<<v.letter_<<v.len_;
|
||||
break;
|
||||
}
|
||||
s.cmdLine_ += os.str();
|
||||
}
|
||||
std::list<std::string>::iterator first = s.values_.begin();
|
||||
// We add to the iterator as much values as we can, limited to the length
|
||||
// specified (if different of -1)
|
||||
int n = v.len_ != -1?v.len_:s.values_.size();
|
||||
while (first != s.values_.end() && n-->0)
|
||||
{
|
||||
// Read the value from the string *first
|
||||
ValueParser<T> p;
|
||||
*(v.value_++) = p(*first );
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
// The value we just removed was maybe "remembered" by an option so we
|
||||
// remove it now.
|
||||
for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
{
|
||||
if (jter->second == first)
|
||||
{
|
||||
jter->second = s.values_.end();
|
||||
}
|
||||
}
|
||||
++first;
|
||||
}
|
||||
// Check if we have enough values
|
||||
if (n != 0)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Expecting "<<v.len_<<" values";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
// Erase the values parsed
|
||||
s.values_.erase(s.values_.begin(),first);
|
||||
return s;
|
||||
}
|
||||
inline bool
|
||||
argstream::defaultErrorHandling(bool ignoreUnused) const
|
||||
{
|
||||
if (helpRequested_)
|
||||
{
|
||||
std::cout<<usage();
|
||||
exit(1);
|
||||
}
|
||||
if (!isOk_)
|
||||
{
|
||||
std::cerr<<errorLog();
|
||||
exit(1);
|
||||
}
|
||||
if (!ignoreUnused &&
|
||||
(!values_.empty() || !options_.empty()))
|
||||
{
|
||||
std::cerr<<"Unused arguments"<<std::endl;
|
||||
exit(1);
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
};
|
||||
#endif // ARGSTREAM_H
|
||||
|
@ -101,9 +101,9 @@ bool NotifyTxt::askForPluginConfirmation(const std::string& plugin_file_name, co
|
||||
return a == 'y' ;
|
||||
}
|
||||
|
||||
bool NotifyTxt::askForPassword(const std::string& key_details, bool prev_is_bad, std::string& password)
|
||||
bool NotifyTxt::askForPassword(const std::string& question, bool prev_is_bad, std::string& password)
|
||||
{
|
||||
char *passwd = getpass(("Please enter GPG password for key "+key_details+": ").c_str()) ;
|
||||
char *passwd = getpass(question.c_str()) ;
|
||||
password = passwd;
|
||||
|
||||
return !password.empty();
|
||||
|
@ -42,7 +42,7 @@ class NotifyTxt: public NotifyBase
|
||||
virtual void notifyListChange(int list, int type);
|
||||
virtual void notifyErrorMsg(int list, int sev, std::string msg);
|
||||
virtual void notifyChat();
|
||||
virtual bool askForPassword(const std::string& key_details, bool prev_is_bad, std::string& password);
|
||||
virtual bool askForPassword(const std::string& question, bool prev_is_bad, std::string& password);
|
||||
virtual bool askForPluginConfirmation(const std::string& plugin_file, const std::string& plugin_hash);
|
||||
|
||||
virtual void notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleFileInfo>& found_files);
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "notifytxt.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <util/argstream.h>
|
||||
#include <iostream>
|
||||
#ifdef WINDOWS_SYS
|
||||
#include <winsock2.h>
|
||||
@ -53,6 +54,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RS_SSH_SERVER
|
||||
void generatePasswordHash() ;
|
||||
#endif
|
||||
|
||||
/* Basic instructions for running libretroshare as background thread.
|
||||
* ******************************************************************* *
|
||||
* This allows your program to communicate with authenticated peers.
|
||||
@ -102,7 +107,6 @@ int main(int argc, char **argv)
|
||||
bool enableRpc = false;
|
||||
bool enableSsh = false;
|
||||
bool enableSshHtml = false;
|
||||
bool enableSshPwd = false;
|
||||
bool enableTerminal = false;
|
||||
bool enableSshRsa = false;
|
||||
bool genPwdHash = false;
|
||||
@ -112,167 +116,75 @@ int main(int argc, char **argv)
|
||||
std::string sshPortStr = "0";
|
||||
|
||||
uint16_t extPort = 0;
|
||||
uint16_t sshPort = 7022;
|
||||
bool extPortSet = false;
|
||||
bool displayRPCInfo = false ;
|
||||
|
||||
while((c = getopt(argc, argv,"ChTL:P:K:GS:E:")) != -1)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'C':
|
||||
enableRpc = true;
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'S':
|
||||
enableSsh = true;
|
||||
sshPortStr = optarg; // no longer optional.
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'E':
|
||||
extPort = atoi(optarg);
|
||||
extPortSet = true;
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'H':
|
||||
enableSshHtml = true;
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'T':
|
||||
enableTerminal = true;
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'L':
|
||||
sshUser = optarg;
|
||||
strictCheck = false;
|
||||
break;
|
||||
case 'P':
|
||||
enableSshPwd = true;
|
||||
sshPwdHash = optarg;
|
||||
strictCheck = false;
|
||||
break;
|
||||
#if 0 // NOT FINISHED YET.
|
||||
case 'K':
|
||||
enableSshRsa = true;
|
||||
sshRsaFile = optarg;
|
||||
strictCheck = false;
|
||||
break;
|
||||
argstream as(argc,argv) ;
|
||||
|
||||
as >> option('X',"enable-ssh" ,enableSsh ,"Enable SSH" )
|
||||
>> option('T',"enable-terminal",enableTerminal ,"Enable terminal interface." )
|
||||
>> option('C',"enable-rpc" ,enableRpc ,"Enable RPC protocol. To be used with e.g. -X (SSH).")
|
||||
>> option('G',"gen-password" ,genPwdHash ,"Generate password hash (to supply to option -P)")
|
||||
#if 0
|
||||
>> option('H',"enable-ssh-html",enableSshHtml ,"Enable SSH html." )
|
||||
#endif
|
||||
case 'G':
|
||||
genPwdHash = true;
|
||||
break;
|
||||
case 'h':
|
||||
/* nogui help */
|
||||
std::cerr << argv[0] << std::endl;
|
||||
std::cerr << "Specific Help Options: " << std::endl;
|
||||
std::cerr << "\t-G Generate a Password Hash for SSH Server" << std::endl;
|
||||
std::cerr << "\t-T Enable Terminal Interface" << std::endl;
|
||||
std::cerr << "\t-S <port> Enable SSH Server on specified port" << std::endl;
|
||||
std::cerr << "\t-E <port> Specify Alternative External Port (provided to Clients)" << std::endl;
|
||||
std::cerr << "\t-L <user> Specify SSH login user (default:user)" << std::endl;
|
||||
std::cerr << "\t-P <pwdhash> Enable SSH login via Password" << std::endl;
|
||||
std::cerr << "\t-C Enable RPC Protocol (requires -S too)" << std::endl;
|
||||
//std::cerr << "\t-K [rsapubkeyfile] Enable SSH login via RSA key" << std::endl;
|
||||
//std::cerr << "\t NB: Two Factor Auth, specify both -P & -K" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\t To setup rs-nogui as a SSH Server is a three step process: " << std::endl;
|
||||
std::cerr << "\t 1) \"ssh-keygen -t rsa -f rs_ssh_host_rsa_key\" " << std::endl;
|
||||
std::cerr << "\t 2) \"./retroshare-nogui -G\" " << std::endl;
|
||||
std::cerr << "\t 3) \"./retroshare-nogui -S [port] -L <user> -P <passwordhash>\" " << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Further Options ";
|
||||
/* libretroshare will call exit(1) after printing its options */
|
||||
break;
|
||||
>> parameter('S',"ssh-port" ,sshPort ,"port" ,"SSH port to contact the interface.",false)
|
||||
>> parameter('E',"ext-port" ,extPort ,"port" ,"Specify Alternative External Port (provided to Clients)",false)
|
||||
>> parameter('L',"ssh-user" ,sshUser ,"name" ,"Ssh login user",false)
|
||||
>> parameter('P',"ssh-p-hash" ,sshPwdHash ,"hash" ,"Ssh login password hash (Generated by retroshare-nogui -G)",false)
|
||||
>> parameter('K',"ssh-key-file" ,sshRsaFile ,"RSA key file", "RSA key file for SSH login (not yet implemented).",false )// NOT FINISHED YET.
|
||||
|
||||
default:
|
||||
/* let others through - for libretroshare */
|
||||
break;
|
||||
}
|
||||
>> help() ;
|
||||
|
||||
// Normally argstream would handle this by itself, if we called
|
||||
// as.defaultErrorHandling() ;
|
||||
//
|
||||
// but we have other parameter handling functions after, so we don't want to quit if help is requested.
|
||||
//
|
||||
if (as.helpRequested())
|
||||
{
|
||||
std::cerr << "\nSpecific Help Options:" << std::endl;
|
||||
std::cerr << as.usage() << std::endl;
|
||||
std::cerr << "\t To setup rs-nogui as a SSH Server is a three step process: " << std::endl;
|
||||
std::cerr << "\t 1) Generate a RSA keypair in the current directory: \"ssh-keygen -t rsa -f rs_ssh_host_rsa_key\" " << std::endl;
|
||||
std::cerr << "\t 2) Generate a password hash for the RPC login: \"./retroshare-nogui -G\" " << std::endl;
|
||||
std::cerr << "\t 3) Launch the RS with remote control enabled: \"./retroshare-nogui -X/-T [-C] -S [port] -L <user> -P <passwordhash>\" " << std::endl;
|
||||
|
||||
std::cerr << "\nAdditional options: \n" << std::endl;
|
||||
}
|
||||
if (!as.isOk())
|
||||
{
|
||||
std::cerr << as.errorLog();
|
||||
return 1;
|
||||
}
|
||||
// reset optind for Retroshare commandline arguments.
|
||||
optind = 1;
|
||||
|
||||
if (genPwdHash)
|
||||
{
|
||||
std::string saltBin;
|
||||
std::string pwdHashRadix64;
|
||||
std::string sshPwdForHash = "";
|
||||
|
||||
std::cout << "Type in your Password:" << std::flush;
|
||||
char pwd[1024];
|
||||
if (!fgets(pwd, 1024, stdin))
|
||||
{
|
||||
std::cerr << "Error Reading Password";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// strip newline.
|
||||
for(int i = 0; (i < 1024) && (pwd[i] != '\n') && (pwd[i] != '\0'); i++)
|
||||
{
|
||||
sshPwdForHash += pwd[i];
|
||||
}
|
||||
|
||||
std::cerr << "Chosen Password : " << sshPwdForHash;
|
||||
std::cerr << std::endl;
|
||||
|
||||
|
||||
GenerateSalt(saltBin);
|
||||
if (!GeneratePasswordHash(saltBin, sshPwdForHash, pwdHashRadix64))
|
||||
{
|
||||
std::cerr << "Error Generating Password Hash, password probably too short";
|
||||
std::cerr << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "Generated Password Hash for rs-nogui: ";
|
||||
std::cout << pwdHashRadix64;
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
/* checking match */
|
||||
if (CheckPasswordHash(pwdHashRadix64, sshPwdForHash))
|
||||
{
|
||||
std::cerr << "Passed Check Okay!";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: Failed CheckPassword!";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
std::cerr << "Usage:";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " - for SSH access: ./retroshare-nogui -S [port] -L <username> -P " << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " - for RPC access: ./retroshare-nogui -C -S [port] -L <username> -P " << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
exit(0);
|
||||
generatePasswordHash() ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
/* enforce conditions */
|
||||
if (((enableSshRsa) || (enableSshPwd)) && (!enableSsh))
|
||||
if ((!sshRsaFile.empty() || !sshPwdHash.empty()) && (!enableSsh))
|
||||
{
|
||||
std::cerr << "ERROR: SSH Server (-S) must be enabled to specify SSH Pwd (-P) or SSH RSA (-K)";
|
||||
std::cerr << "ERROR: SSH Server (-X) must be enabled to specify SSH Pwd (-P) or SSH RSA (-K)";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
if (enableSsh && (!enableSshRsa) && (!enableSshPwd))
|
||||
if (enableSsh && (!enableSshRsa) && sshPwdHash.empty())
|
||||
{
|
||||
std::cerr << "ERROR: One of (or both) SSH Pwd (-P) and SSH RSA (-K) must be specified with SSH Server (-S)";
|
||||
std::cerr << "ERROR: One of (or both) SSH Pwd (-P) and SSH RSA (-K) must be specified with SSH Server (-X)";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
if (enableRpc && (!enableSsh))
|
||||
{
|
||||
std::cerr << "ERROR: RPC Mode (-C) requires SSH Server (-S) enabled";
|
||||
std::cerr << "ERROR: RPC Mode (-C) requires SSH Server (-X) enabled";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
|
||||
@ -291,12 +203,8 @@ int main(int argc, char **argv)
|
||||
|
||||
}
|
||||
|
||||
if (enableSshPwd)
|
||||
{
|
||||
/* try parse it */
|
||||
/* TODO */
|
||||
|
||||
}
|
||||
#else
|
||||
std::cerr << "\nRetroshare command line interface." << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
@ -372,7 +280,7 @@ int main(int argc, char **argv)
|
||||
//ssh->adduser("anrsuser", "test");
|
||||
}
|
||||
|
||||
if (enableSshPwd)
|
||||
if (!sshPwdHash.empty())
|
||||
{
|
||||
ssh->adduserpwdhash(sshUser, sshPwdHash);
|
||||
}
|
||||
@ -385,8 +293,6 @@ int main(int argc, char **argv)
|
||||
// NASTY GLOBAL VARIABLE HACK - NEED TO THINK OF A BETTER SYSTEM.
|
||||
RpcProtoSystem::mExtPort = extPort;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* Start-up libretroshare server threads */
|
||||
@ -470,3 +376,71 @@ int main(int argc, char **argv)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef RS_SSH_SERVER
|
||||
void generatePasswordHash()
|
||||
{
|
||||
std::string saltBin;
|
||||
std::string pwdHashRadix64;
|
||||
std::string sshPwdForHash = "";
|
||||
|
||||
std::string passwd1,passwd2 ;
|
||||
|
||||
if(!NotifyTxt().askForPassword("Type your password (at least 8 chars) : ",false,passwd1)) exit(1) ;
|
||||
|
||||
if(passwd1.length() < 8)
|
||||
{
|
||||
std::cerr << "Password must be at least 8 characters long." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!NotifyTxt().askForPassword("Type your password (checking) : ",false,passwd2)) exit(1) ;
|
||||
|
||||
if(passwd1 != passwd2)
|
||||
{
|
||||
std::cerr << "Passwords differ. Please retry." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sshPwdForHash = passwd1 ;
|
||||
|
||||
//std::cerr << "Chosen Password : " << sshPwdForHash;
|
||||
std::cerr << std::endl;
|
||||
|
||||
GenerateSalt(saltBin);
|
||||
if (!GeneratePasswordHash(saltBin, sshPwdForHash, pwdHashRadix64))
|
||||
{
|
||||
std::cerr << "Error Generating Password Hash, password probably too short";
|
||||
std::cerr << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "Generated Password Hash for rs-nogui: ";
|
||||
std::cout << pwdHashRadix64;
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
/* checking match */
|
||||
if (CheckPasswordHash(pwdHashRadix64, sshPwdForHash))
|
||||
{
|
||||
std::cerr << "Passed Check Okay!";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: Failed CheckPassword!";
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
std::cerr << "Usage:";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " - for SSH access: ./retroshare-nogui -X -S [port] -L <username> -P " << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " - for RPC access: ./retroshare-nogui -C -S [port] -L <username> -P " << pwdHashRadix64;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user