E-MailRelay

garg.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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/// \file garg.cpp
19///
20
21#include "gdef.h"
22#include "garg.h"
23#include "gprocess.h"
24#include "gscope.h"
25#include "gpath.h"
26#include "gstr.h"
27#include "glog.h"
28#include "gassert.h"
29#include <cstring>
30
31 G::Path G::Arg::m_v0 ;
32 G::Path 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
39 for( int i = 0 ; i < argc ; i++ )
40 m_array.emplace_back( argv[i] ) ;
41
42 if( m_v0.empty() && !m_array.empty() )
43 {
44 m_v0 = Path( m_array[0] ) ;
45 m_cwd = Process::cwd( std::nothrow ) ; // don't throw yet - we may "cd /" to deamonise
46 }
47}
48
49 G::Arg::Arg( const StringArray & args ) :
50 m_array(args)
51{
52}
53
54#ifndef G_LIB_SMALL
55 G::Arg::Arg( const Path & argv0 , const std::string & command_line_tail )
56{
57 if( argv0.empty() )
58 throw Exception( "invalid path for this executable" ) ;
59 parseImp( command_line_tail ) ;
60 m_array.insert( m_array.begin() , argv0.str() ) ;
61}
62#endif
63
64 G::Arg::Arg( const std::string & command_line )
65{
66 G_ASSERT( !command_line.empty() ) ;
67 parseImp( command_line ) ;
68}
69
70 G::Arg G::Arg::windows()
71{
72 Arg arg( (Windows()) ) ;
73 if( m_v0.empty() && !arg.m_array.empty() )
74 {
75 m_v0 = Path( arg.m_array[0] ) ;
76 m_cwd = Process::cwd( std::nothrow ) ;
77 }
78 return arg ;
79}
80
81#ifndef G_LIB_SMALL
82 G::Path G::Arg::v0()
83{
84 return m_v0 ;
85}
86#endif
87
88 G::StringArray G::Arg::array( unsigned int shift ) const
89{
90 StringArray result = m_array ;
91 while( !result.empty() && shift-- )
92 result.erase( result.begin() ) ;
93 return result ;
94}
95
96 bool G::Arg::contains( std::string_view option , std::size_t option_args , bool cs ) const
97{
98 return find( cs , option , option_args , nullptr ) != 0U ;
99}
100
101#ifndef G_LIB_SMALL
102std::size_t G::Arg::count( std::string_view option ) const
103{
104 return find( true , option , 0U , nullptr ) ;
105}
106#endif
107
108std::size_t G::Arg::find( bool cs , std::string_view option , std::size_t option_args ,
109 std::size_t * index_p ) const
110{
111 std::size_t count = 0U ;
112 for( std::size_t i = 1U ; i < m_array.size() ; i++ ) // start from v[1]
113 {
114 if( strmatch(cs,option,m_array[i]) && (i+option_args) < m_array.size() )
115 {
116 count++ ;
117 if( index_p != nullptr )
118 *index_p = i ;
119 i += option_args ;
120 }
121 }
122 return count ;
123}
124
125std::size_t G::Arg::match( const std::string & prefix ) const
126{
127 for( std::size_t i = 1U ; i < m_array.size() ; i++ )
128 {
129 if( Str::headMatch(m_array[i],prefix) )
130 {
131 return i ;
132 }
133 }
134 return 0U ;
135}
136
137 bool G::Arg::strmatch( bool cs , std::string_view s1 , std::string_view s2 )
138{
139 return cs ? (s1==s2) : Str::imatch(s1,s2) ;
140}
141
142 bool G::Arg::remove( std::string_view option , std::size_t option_args )
143{
144 std::size_t i = 0U ;
145 const bool found = find( true , option , option_args , &i ) != 0U ;
146 if( found )
147 removeAt( i , option_args ) ;
148 return found ;
149}
150
151std::string G::Arg::removeValue( std::string_view option , const std::string & default_ )
152{
153 std::size_t option_args = 1U ;
154 std::size_t i = 0U ;
155 const bool found = find( true , option , option_args , &i ) != 0U ;
156 return found ? removeAt( i , option_args ) : default_ ;
157}
158
159std::string G::Arg::removeAt( std::size_t option_index , std::size_t option_args )
160{
161 std::string value ;
162 if( option_index > 0U && (option_index+option_args) < m_array.size() )
163 {
164 value = v( option_index + (option_args?1U:0U) , std::string() ) ;
165 auto p = m_array.begin() ;
166 for( std::size_t i = 0U ; i < option_index ; i++ ) ++p ; // (rather than cast)
167 p = m_array.erase( p ) ;
168 for( std::size_t i = 0U ; i < option_args && p != m_array.end() ; i++ )
169 p = m_array.erase( p ) ;
170 }
171 return value ;
172}
173
174std::size_t G::Arg::index( std::string_view option , std::size_t option_args ,
175 std::size_t default_ ) const
176{
177 std::size_t i = 0U ;
178 const bool found = find( true , option , option_args , &i ) != 0U ;
179 return found ? i : default_ ;
180}
181
182std::size_t G::Arg::c() const
183{
184 return m_array.size() ;
185}
186
187std::string G::Arg::v( std::size_t i ) const
188{
189 G_ASSERT( i < m_array.size() ) ;
190 return m_array.at(i) ;
191}
192
193std::string G::Arg::v( std::size_t i , const std::string & default_ ) const
194{
195 return i < m_array.size() ? m_array.at(i) : default_ ;
196}
197
198std::string G::Arg::prefix() const
199{
200 G_ASSERT( !m_array.empty() ) ;
201 Path path( m_array.at(0U) ) ;
202 return path.withoutExtension().basename() ;
203}
204
205 const char * G::Arg::prefix( char ** argv ) noexcept
206{
207 if( argv == nullptr ) return "" ;
208 const char * exe = argv[0] ;
209 if( exe == nullptr || exe[0] == '\0' ) return "" ;
210 const char * p1 = std::strrchr( exe , '/' ) ;
211 const char * p2 = std::strrchr( exe , '\\' ) ;
212 p1 = p1 == nullptr ? exe : (p1+1U) ;
213 p2 = p2 == nullptr ? exe : (p2+1U) ;
214 return p1 > p2 ? p1 : p2 ;
215}
216
217 void G::Arg::parseImp( const std::string & command_line )
218{
219 constexpr std::string_view ws( " \t" , 2U ) ;
220 constexpr std::string_view nbws( "\0\0" , 2U ) ;
221 static_assert( ws.size() == nbws.size() , "" ) ;
222 const char esc = '\\' ;
223 const char qq = '\"' ;
224 Str::splitIntoTokens( Str::dequote(command_line,qq,esc,ws,nbws) , m_array , ws , esc ) ;
225 Str::replace( m_array , '\0' , ' ' ) ;
226}
227
228 G::Path G::Arg::exe()
229{
230 return exeImp( true ) ;
231}
232
233#ifndef G_LIB_SMALL
234 G::Path G::Arg::exe( std::nothrow_t )
235{
236 return exeImp( false ) ;
237}
238#endif
239
240 G::Path G::Arg::exeImp( bool do_throw )
241{
242 Path process_exe = Process::exe() ;
243 if( !process_exe.empty() )
244 {
245 return process_exe ;
246 }
247 else if( m_v0.isAbsolute() )
248 {
249 return m_v0 ;
250 }
251 else if( !m_cwd.empty() )
252 {
253 return Path::join(m_cwd,m_v0).collapsed() ;
254 }
255 else if( do_throw )
256 {
257 throw Exception( "cannot determine the absolute path of the current executable" ,
258 G::is_windows() ? "" : "try mounting procfs" ) ;
259 }
260 else
261 {
262 return {} ;
263 }
264}
265
266#ifndef G_LIB_SMALL
267G::StringArray::const_iterator G::Arg::cbegin() const
268{
269 return m_array.size() <= 1U ? cend() : std::next( m_array.cbegin() ) ;
270}
271#endif
272
273G::StringArray::const_iterator G::Arg::cend() const
274{
275 return m_array.cend() ;
276}
277
G::Arg
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
Definition: garg.h:50
G::Arg::c
std::size_t c() const
Returns the number of tokens in the command line, including the program name.
Definition: garg.cpp:182
G::Arg::windows
static Arg windows()
Factory function for Windows using GetCommandLineW().
Definition: garg.cpp:70
G::Arg::match
std::size_t match(const std::string &prefix) const
Returns the index of the first argument that matches the given prefix.
Definition: garg.cpp:125
G::Arg::v
std::string v(std::size_t i) const
Returns the i'th argument.
Definition: garg.cpp:187
G::Arg::index
std::size_t index(std::string_view option, std::size_t option_args=0U, std::size_t default_=0U) const
Returns the index of the given option.
Definition: garg.cpp:174
G::Arg::Arg
Arg(int argc, char **argv)
Constructor taking argc/argv directly from main().
Definition: garg.cpp:34
G::Arg::count
std::size_t count(std::string_view option) const
Returns the number of times the given string appears in the list of arguments.
Definition: garg.cpp:102
G::Arg::removeAt
std::string removeAt(std::size_t option_index, std::size_t option_args=0U)
Removes the given argument and the following 'option_args' ones.
Definition: garg.cpp:159
G::Arg::cend
StringArray::const_iterator cend() const
Returns the end iterator.
Definition: garg.cpp:273
G::Arg::prefix
std::string prefix() const
Returns the basename of v(0) without any extension.
Definition: garg.cpp:198
G::Arg::removeValue
std::string removeValue(std::string_view option, const std::string &default_={})
Removes the given single-valued option and its value.
Definition: garg.cpp:151
G::Arg::array
StringArray array(unsigned int shift=0U) const
Returns the arguments as a string array, with an optional shift.
Definition: garg.cpp:88
G::Arg::remove
bool remove(std::string_view option, std::size_t option_args=0U)
Removes the given option and its arguments.
Definition: garg.cpp:142
G::Arg::exe
static Path exe()
Returns Process::exe() or in exceptional circumstances an absolute path constructed from v0() and the...
Definition: garg.cpp:228
G::Arg::contains
bool contains(std::string_view option, std::size_t 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:96
G::Arg::cbegin
StringArray::const_iterator cbegin() const
Returns a begin iterator, advanced to exclude argv0.
Definition: garg.cpp:267
G::Arg::v0
static Path v0()
Returns a copy of argv[0] from the first call to the argc/argv constructor overload or windows().
Definition: garg.cpp:82
G::Exception
A general-purpose exception class derived from std::exception and containing an error message.
Definition: gexception.h:64
G::Path
A Path object represents a file system path.
Definition: gpath.h:82
G::Path::join
static Path join(const StringArray &parts)
Builds a path from a set of parts.
Definition: gpath.cpp:434
G::Path::basename
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
Definition: gpath.cpp:339
G::Path::withoutExtension
Path withoutExtension() const
Returns a path without the basename extension, if any.
Definition: gpath.cpp:357
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:459
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.h:243
G::Path::empty
bool empty() const noexcept
Returns true if the path is empty.
Definition: gpath.h:237
G::Process::cwd
static Path cwd()
Returns the current working directory. Throws on error.
Definition: gprocess_unix.cpp:210
G::Process::exe
static Path exe()
Returns the absolute path of the current executable, independent of the argv array passed to main().
Definition: gprocess_unix.cpp:265
G::Str::splitIntoTokens
static void splitIntoTokens(const std::string &in, StringArray &out, std::string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
Definition: gstr.cpp:1119
G::Str::imatch
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
Definition: gstr.cpp:1415
G::Str::headMatch
static bool headMatch(std::string_view in, std::string_view head) noexcept
Returns true if the string has the given start (or head is empty).
Definition: gstr.cpp:1359
G::Str::dequote
static std::string dequote(const std::string &, char qq='\"' , char esc = '\\' , std::string_view ws = Str::ws() , std::string_view nbws = Str::ws() )
Dequotes a string by removing unescaped quotes and escaping quoted whitespace, so "qq-aaa-esc-qq-bbb-...
Definition: gstr.cpp:128
G::Str::replace
static bool replace(std::string &s, std::string_view from, std::string_view to, std::size_t *pos_p=nullptr)
A std::string_view overload.
Definition: gstr.cpp:226
garg.h
gassert.h
glog.h
gpath.h
gprocess.h
gscope.h
gstr.h
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30