49void G::BatchFile::init(
const Path & path )
51 std::ifstream stream ;
54 throw Error(
"cannot open batch file" , path.
str() ) ;
55 m_raw_line = readFrom( stream , path.
str() ) ;
56 auto parse_result = parse( m_raw_line ) ;
57 if( !parse_result.error.empty() )
58 throw Error( parse_result.error , path.
str() ) ;
59 m_name = parse_result.name ;
60 m_line = parse_result.line ;
61 m_args = split( m_line ) ;
64void G::BatchFile::clear()
74 return m_line.empty() ;
77bool G::BatchFile::ignorable(
const std::string & trimmed_line )
80 trimmed_line.empty() ||
81 Str::lower(trimmed_line+
" ").find(
"@echo ") == 0U ||
82 Str::lower(trimmed_line+
" ").find(
"rem ") == 0U ;
85bool G::BatchFile::relevant(
const std::string & trimmed_line )
87 return !ignorable( trimmed_line ) ;
90std::string G::BatchFile::readFrom( std::istream & stream ,
const std::string & stream_name ,
bool do_throw )
93 while( stream.good() )
105 throw Error(
"too many lines in batch file" , stream_name ) ;
114 throw Error(
"batch file is empty" , stream_name ) ;
121G::BatchFile::ParseResult G::BatchFile::parse(
const std::string & line_in )
127 std::string line = line_in ;
130 using size_type = std::string::size_type ;
131 size_type
const npos = std::string::npos ;
132 std::string ws = sv_to_string(
Str::ws() ) ;
134 std::string start =
"start " ;
135 size_type start_pos =
Str::lower(line).find(start) ;
136 size_type command_pos = start_pos == npos ? 0U : line.find_first_not_of( ws , start_pos+start.size() ) ;
138 bool named = start_pos != npos && line.at(command_pos) ==
'"' ;
141 std::size_t name_start_pos = command_pos ;
142 std::size_t name_end_pos = line.find(
'\"' , name_start_pos+1U ) ;
143 if( name_end_pos == npos )
144 return {{},{},
"mismatched quotes in batch file"} ;
145 if( (name_end_pos+2U) >= line.size() || line.at(name_end_pos+1U) !=
' ' )
146 return {{},{},
"invalid window name in batch file"} ;
148 result.name = line.substr( name_start_pos+1U , name_end_pos-(name_start_pos+1U) ) ;
149 dequote( result.name ) ;
152 command_pos = line.find_first_not_of( ws , name_end_pos+2U ) ;
155 if( command_pos != npos )
156 line.erase( 0U , command_pos ) ;
183 constexpr char qq =
'\"' ;
185 for(
bool in_quote =
false ; i < m_line.size() ; i++ )
188 if( c == qq && !in_quote )
192 else if(
Str::ws().find(c) != std::string::npos && !in_quote )
198void G::BatchFile::dequote( std::string & s )
200 if( s.size() >= 2U && s.find(
'\"') == 0U && (s.rfind(
'\"')+1U) == s.size() )
201 s = s.substr( 1U , s.size()-2U ) ;
206 G_ASSERT( !args.empty() ) ;
208 throw Error(
"invalid contents for startup batch file" ) ;
210 std::string name = name_in ;
218 std::string start_line ;
220 std::ostringstream ss ;
222 for(
const auto & arg : args )
226 start_line = ss.str() ;
231 BatchFile on_disk( path , std::nothrow ) ;
232 if( start_line != on_disk.m_raw_line )
236 std::ofstream stream ;
239 throw Error(
"cannot create batch file" , path.
str() ) ;
241 stream << start_line <<
"\r\n" ;
244 throw Error(
"cannot write batch file" , path.
str() ) ;
253std::string G::BatchFile::percents(
const std::string & s )
255 std::string result( s ) ;
260std::string G::BatchFile::quote(
const std::string & s )
263 s.find(
'\"') == std::string::npos && s.find_first_of(
" \t") != std::string::npos ?
264 "\"" + s +
"\"" : s ;
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
StringArray array(unsigned int shift=0U) const
Returns the arguments as a string array, with an optional shift.
A class for reading and writing windows-style startup batch files containing a single command-line,...
const StringArray & args() const
Returns the startup command-line broken up into de-quoted pieces.
bool empty() const
Returns true if line() is empty.
std::size_t lineArgsPos() const
Returns the position in line() where the arguments start.
std::string name() const
Returns the "start" window name, if any.
BatchFile(const Path &)
Constructor that reads from a file.
std::string line() const
Returns the main command-line from within the batchfile, with normalised spaces, without any "start" ...
static void write(const Path &new_batch_file, const StringArray &args, const std::string &start_window_name={}, bool do_backup=false)
Writes a startup batch file, including a "start" prefix.
An overload discriminator for G::File::open().
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
static Path backup(const Path &from, std::nothrow_t)
Creates a backup copy of the given file in the same directory and with a lightly-mangled filename.
A Path object represents a file system path.
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
Path withoutExtension() const
Returns a path without the basename extension, if any.
std::string str() const
Returns the path string.
static std::string lower(std::string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
static std::string & trim(std::string &s, std::string_view ws)
Trims both ends of s, taking off any of the 'ws' characters.
static std::string unique(const std::string &s, char c, char r)
Returns a string with repeated 'c' characters replaced by one 'r' character.
static std::string readLineFrom(std::istream &stream, std::string_view eol={})
Reads a line from the stream using the given line terminator.
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
static std::string_view ws() noexcept
Returns a string of standard whitespace characters.
std::string toCodePageOem(std::string_view)
Converts from UTF-8 to the active OEM codepage (see GetOEMCP(), 850 on unix).
std::string fromCodePageOem(std::string_view)
Converts from the active OEM codepage (see GetOEMCP(), 850 on unix) to UTF-8.
std::vector< std::string > StringArray
A std::vector of std::strings.