E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

garg.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // garg.cpp
19 //
20
21 #include "gdef.h"
22 #include "garg.h"
23 #include "gprocess.h"
24 #include "gpath.h"
25 #include "gstr.h"
26 #include "gdebug.h"
27 #include "gassert.h"
28 #include <cstring>
29
30 bool G::Arg::m_first = true ;
31 std::string G::Arg::m_v0 ;
32 std::string G::Arg::m_cwd ;
33
34 G::Arg::Arg( int argc , char *argv[] )
35 {
36 G_ASSERT( argc > 0 ) ;
37 G_ASSERT( argv != nullptr ) ;
38 for( int i = 0 ; i < argc ; i++ )
39 m_array.push_back( argv[i] ) ;
40
41 if( m_first )
42 {
43 m_v0 = std::string( argv[0] ) ;
44 m_cwd = Process::cwd(true/*nothrow*/) ; // don't throw yet - we may "cd /" to deamonise
45 m_first = false ;
46 }
47 }
48
49 G::Arg::Arg( const StringArray & args ) :
50 m_array(args)
51 {
52 }
53
54 G::Arg::Arg( const Arg & other ) :
55 m_array(other.m_array)
56 {
57 }
58
59 G::Arg::~Arg()
60 {
61 }
62
63 G::Arg::Arg()
64 {
65 // now use parse()
66 }
67
68 void G::Arg::parse( HINSTANCE , const std::string & command_line_tail )
69 {
70 m_array.clear() ;
71 m_array.push_back( Process::exe() ) ;
72 parseCore( command_line_tail ) ;
73 }
74
75 void G::Arg::parse( const std::string & command_line )
76 {
77 G_ASSERT( !command_line.empty() ) ;
78 m_array.clear() ;
79 parseCore( command_line ) ;
80 }
81
82 void G::Arg::reparse( const std::string & command_line_tail )
83 {
84 while( m_array.size() > 1U ) m_array.pop_back() ;
85 parseCore( command_line_tail ) ;
86 }
87
88 std::string G::Arg::v0()
89 {
90 return m_v0 ;
91 }
92
93 G::Arg & G::Arg::operator=( const Arg & rhs )
94 {
95 Arg tmp( rhs ) ;
96 m_array.swap( tmp.m_array ) ;
97 return *this ;
98 }
99
100 G::StringArray G::Arg::array( unsigned int shift ) const
101 {
102 G::StringArray result = m_array ;
103 while( !result.empty() && shift-- )
104 result.erase( result.begin() ) ;
105 return result ;
106 }
107
108 bool G::Arg::contains( const std::string & option , size_type option_args , bool cs ) const
109 {
110 return find( cs , option , option_args , nullptr ) ;
111 }
112
113 bool G::Arg::find( bool cs , const std::string & option , size_type option_args , size_type * index_p ) const
114 {
115 for( size_type i = 1 ; i < m_array.size() ; i++ ) // start from v[1]
116 {
117 if( match(cs,option,m_array[i]) && (i+option_args) < m_array.size() )
118 {
119 if( index_p != nullptr )
120 *index_p = i ;
121 return true ;
122 }
123 }
124 return false ;
125 }
126
127 bool G::Arg::match( bool cs , const std::string & s1 , const std::string & s2 )
128 {
129 return cs ? (s1==s2) : (Str::upper(s1)==Str::upper(s2)) ;
130 }
131
132 bool G::Arg::remove( const std::string & option , size_type option_args )
133 {
134 size_type i = 0U ;
135 const bool found = find( true , option , option_args , &i ) ;
136 if( found )
137 removeAt( i , option_args ) ;
138 return found ;
139 }
140
141 void G::Arg::removeAt( size_type option_index , size_type option_args )
142 {
143 G_ASSERT( option_index > 0U && option_index < m_array.size() ) ;
144 if( option_index > 0U && option_index < m_array.size() )
145 {
146 StringArray::iterator p = m_array.begin() ;
147 for( size_type i = 0U ; i < option_index ; i++ ) ++p ; // (rather than cast)
148 p = m_array.erase( p ) ;
149 for( size_type i = 0U ; i < option_args && p != m_array.end() ; i++ )
150 p = m_array.erase( p ) ;
151 }
152 }
153
154 G::Arg::size_type G::Arg::index( const std::string & option , size_type option_args ) const
155 {
156 size_type i = 0U ;
157 const bool found = find( true , option , option_args , &i ) ;
158 return found ? i : 0U ;
159 }
160
161 G::Arg::size_type G::Arg::c() const
162 {
163 return m_array.size() ;
164 }
165
166 std::string G::Arg::v( size_type i ) const
167 {
168 G_ASSERT( i < m_array.size() ) ;
169 return m_array.at(i) ;
170 }
171
172 std::string G::Arg::prefix() const
173 {
174 G_ASSERT( m_array.size() > 0U ) ;
175 Path path( m_array.at(0U) ) ;
176 return path.withoutExtension().basename() ;
177 }
178
179 const char * G::Arg::prefix( char * argv [] ) // noexcept
180 {
181 const char * exe = argv[0] ;
182 const char * p1 = std::strrchr( exe , '/' ) ;
183 const char * p2 = std::strrchr( exe , '\\' ) ;
184 p1 = p1 ? (p1+1U) : exe ;
185 p2 = p2 ? (p2+1U) : exe ;
186 return p1 > p2 ? p1 : p2 ;
187 }
188
189 void G::Arg::parseCore( const std::string & command_line )
190 {
191 std::string s( command_line ) ;
192 protect( s ) ;
193 G::Str::splitIntoTokens( s , m_array , " " ) ;
194 unprotect( m_array ) ;
195 dequote( m_array ) ;
196 }
197
198 void G::Arg::protect( std::string & s )
199 {
200 // replace all quoted spaces with a replacement
201 // (could do better: escaped quotes, tabs, single quotes)
202 //G_DEBUG( "G::Arg::protect: before: " << Str::printable(s) ) ;
203 bool in_quote = false ;
204 const char quote = '"' ;
205 const char space = ' ' ;
206 const char replacement = '\0' ;
207 for( std::string::size_type pos = 0U ; pos < s.length() ; pos++ )
208 {
209 if( s.at(pos) == quote ) in_quote = ! in_quote ;
210 if( in_quote && s.at(pos) == space ) s[pos] = replacement ;
211 }
212 //G_DEBUG( "G::Arg::protect: after: " << Str::printable(s) ) ;
213 }
214
215 void G::Arg::unprotect( StringArray & array )
216 {
217 // restore replacements to spaces
218 const char space = ' ' ;
219 const char replacement = '\0' ;
220 for( StringArray::iterator p = array.begin() ; p != array.end() ; ++p )
221 {
222 std::string & s = *p ;
223 G::Str::replaceAll( s , std::string(1U,replacement) , std::string(1U,space) ) ;
224 }
225 }
226
227 void G::Arg::dequote( StringArray & array )
228 {
229 // remove quotes if first and last characters (or equivalent)
230 char qq = '\"' ;
231 for( StringArray::iterator p = array.begin() ; p != array.end() ; ++p )
232 {
233 std::string & s = *p ;
234 if( s.length() > 1U )
235 {
236 std::string::size_type start = s.at(0U) == qq ? 0U : s.find("=\"") ;
237 if( start != std::string::npos && s.at(start) != qq ) ++start ;
238 std::string::size_type end = s.at(s.length()-1U) == qq ? (s.length()-1U) : std::string::npos ;
239 if( start != std::string::npos && end != std::string::npos && start != end )
240 {
241 s.erase( end , 1U ) ; // first!
242 s.erase( start , 1U ) ;
243 }
244 }
245 }
246 }
247
248 std::string G::Arg::exe( bool do_throw )
249 {
250 std::string procfs = Process::exe() ;
251 if( procfs.empty() && ( m_v0.empty() || ( m_cwd.empty() && Path(m_v0).isRelative() ) ) )
252 {
253 if( do_throw )
254 {
255 throw G::Exception( "cannot determine the absolute path of the current executable" ,
256 G::is_windows() ? "" : "try mounting procfs" ) ;
257 }
258 return std::string() ;
259 }
260 else if( procfs.empty() && G::Path(m_v0).isRelative() )
261 {
262 return Path::join(m_cwd,m_v0).collapsed().str() ;
263 }
264 else if( procfs.empty() )
265 {
266 return m_v0 ;
267 }
268 else
269 {
270 return procfs ;
271 }
272 }
273
274 /// \file garg.cpp
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.cpp:290
G::Arg::prefix
std::string prefix() const
Returns the basename of v(0) without any extension.
Definition: garg.cpp:172
G::Arg::~Arg
~Arg()
Destructor.
Definition: garg.cpp:59
G::Path::withoutExtension
Path withoutExtension() const
Returns a path without the basename extension, if any.
Definition: gpath.cpp:328
G::Path::basename
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
Definition: gpath.cpp:310
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
G::Arg::Arg
Arg()
Default constructor. Initialise with parse().
Definition: garg.cpp:63
G::Str::splitIntoTokens
static void splitIntoTokens(const std::string &in, StringArray &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
Definition: gstr.cpp:908
G::Arg::exe
static std::string exe(bool do_throw=true)
Returns Process::exe() or an absolute path constructed from v0().
Definition: garg.cpp:248
garg.h
G::Arg::operator=
Arg & operator=(const Arg &)
Assignment operator.
Definition: garg.cpp:93
G::Path::isRelative
bool isRelative() const
Returns true if the path is a relative path.
Definition: gpath.cpp:305
G::Arg::array
StringArray array(unsigned int shift=0U) const
Returns the arguments a string array, including the program name in the first position.
Definition: garg.cpp:100
G::Arg::v
std::string v(size_type i) const
Returns the i'th argument.
Definition: garg.cpp:166
gstr.h
gassert.h
G::Str::replaceAll
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
Definition: gstr.cpp:195
G::Arg::reparse
void reparse(const std::string &command_line_tail)
Reinitialises the object with the given command-line tail.
Definition: garg.cpp:82
G::Arg::c
size_type c() const
Returns the number of tokens in the command line, including the program name.
Definition: garg.cpp:161
G::Arg::remove
bool remove(const std::string &option, size_type option_args=0U)
Removes the given option and its arguments.
Definition: garg.cpp:132
G::Arg::parse
void parse(HINSTANCE hinstance, const std::string &command_line_tail)
Parses the given command-line tail, splitting it up into an array of tokens.
Definition: garg.cpp:68
G::Str::upper
static std::string upper(const std::string &s)
Returns a copy of 's' in which all Latin-1 lowercase characters have been replaced by uppercase chara...
Definition: gstr.cpp:619
gprocess.h
G::Arg::index
size_type index(const std::string &option, size_type option_args=0U) const
Returns the index of the given option. Returns zero if not present.
Definition: garg.cpp:154
G::Path::collapsed
Path collapsed() const
Returns the path with "foo/.." and "." parts removed, so far as is possible without changing the mean...
Definition: gpath.cpp:415
G::Exception
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:43
gpath.h
G::Arg
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
Definition: garg.h:43
G::Arg::removeAt
void removeAt(size_type option_index, size_type option_args=0U)
Removes the given argument and the following 'option_args' ones.
Definition: garg.cpp:141
G::Arg::contains
bool contains(const std::string &option, size_type option_args=0U, bool case_sensitive=true) const
Returns true if the command line contains the given option with enough command line arguments left to...
Definition: garg.cpp:108
G::Arg::v0
static std::string v0()
Returns a copy of argv[0] from the first call to the constructor that takes argc/argv.
Definition: garg.cpp:88
G::Path
A Path object represents a file system path.
Definition: gpath.h:72
G::Path::join
static Path join(const StringArray &parts)
Builds a path from a set of parts.
Definition: gpath.cpp:390
gdebug.h