Extend options

+ Add global -E option
+ Add %include -e option
~ Move -C option to %include and %resolve
+ Improve comments and messages
This commit is contained in:
zawz 2020-08-28 14:46:42 +02:00
parent ca41c27246
commit af1de6d8fb
11 changed files with 218 additions and 62 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@
/run-tests.sh /run-tests.sh
/Zmakefile /Zmakefile
/TODO /TODO
/lxsh

View file

@ -6,6 +6,8 @@
extern ztd::option_set options; extern ztd::option_set options;
extern bool opt_minimize; extern bool opt_minimize;
extern bool piped; // for cd in substitutions
ztd::option_set gen_options(); ztd::option_set gen_options();
void print_help(const char* arg0); void print_help(const char* arg0);

View file

@ -11,13 +11,16 @@
/* /*
structure: structure:
list_t : condlist[]
block: block:
- group - group
- brace: condlist[] - brace: list_t
- subsh: condlist[] - subsh: list_t
- cmd: arglist[] - cmd: arglist[]
- if - case
- pair<condlist[]>[] - arg (input)
- pair<arg,list_t>[] (cases)
condlist: condlist:
pipeline[] pipeline[]
@ -30,14 +33,11 @@ arglist:
arg: arg:
- raw - raw
- subarg[] - subarg[] split into subarguments in case of subshells
subarg: subarg:
- raw - raw
- variable - block: subshell (substitution)
- block: subshell
*/ */
#define AND_OP false #define AND_OP false
@ -49,6 +49,7 @@ class pipeline;
class arg; class arg;
class subarg; class subarg;
// type pack of condlist
typedef std::vector<condlist> list_t; typedef std::vector<condlist> list_t;
block make_cmd(std::vector<std::string> args); block make_cmd(std::vector<std::string> args);
@ -63,11 +64,14 @@ public:
void setstring(std::string const& str); void setstring(std::string const& str);
// has to be set manually
std::string raw; std::string raw;
std::vector<subarg> sa; std::vector<subarg> sa;
// return if is a string and only one subarg
std::string string(); std::string string();
std::string generate(int ind); std::string generate(int ind);
}; };
@ -99,12 +103,17 @@ public:
class block class block
{ {
public: public:
// type
enum blocktype { none, subshell, brace, main, cmd, function, case_block, for_block, if_block, while_block}; enum blocktype { none, subshell, brace, main, cmd, function, case_block, for_block, if_block, while_block};
blocktype type;
// ctor
block() { type=none; } block() { type=none; }
block(blocktype in) { type=in; } block(blocktype in) { type=in; }
blocktype type;
// subshell/brace/main // subshell/brace/main
list_t cls; list_t cls;
// cmd // cmd
arglist args; arglist args;
@ -143,12 +152,13 @@ public:
condlist() { parallel=false; } condlist() { parallel=false; }
condlist(block const& pl) { parallel=false; this->add(pl);} condlist(block const& pl) { parallel=false; this->add(pl);}
condlist(pipeline const& pl) { parallel=false; this->add(pl);} condlist(pipeline const& pl) { parallel=false; this->add(pl);}
void add(pipeline const& pl, bool or_op=false);
bool parallel; bool parallel; // & at the end
// don't push_back here
std::vector<bool> or_ops; void add(pipeline const& pl, bool or_op=false);
// don't push_back here, use add() instead
std::vector<pipeline> pls; std::vector<pipeline> pls;
std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines
std::string generate(int ind); std::string generate(int ind);
}; };
@ -157,12 +167,15 @@ public:
class subarg class subarg
{ {
public: public:
// type
enum argtype { string, subshell }; enum argtype { string, subshell };
argtype type;
// ctor
subarg(argtype in) { this->type=in; } subarg(argtype in) { this->type=in; }
subarg(std::string const& in="") { type=string; val=in; } subarg(std::string const& in="") { type=string; val=in; }
subarg(block const& in) { type=subshell; sbsh=in; } subarg(block const& in) { type=subshell; sbsh=in; }
argtype type;
// raw string // raw string
std::string val; std::string val;
// subshell // subshell

View file

@ -21,7 +21,8 @@ template<typename ... Args>
std::string strf( const std::string& format, Args ... args ) std::string strf( const std::string& format, Args ... args )
{ {
size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); } if( size <= 0 )
throw std::runtime_error( "Error during formatting." );
std::unique_ptr<char[]> buf( new char[ size ] ); std::unique_ptr<char[]> buf( new char[ size ] );
snprintf( buf.get(), size, format.c_str(), args ... ); snprintf( buf.get(), size, format.c_str(), args ... );
return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
@ -29,4 +30,10 @@ std::string strf( const std::string& format, Args ... args )
std::string delete_brackets(std::string const& in); std::string delete_brackets(std::string const& in);
std::string pwd();
void _exec(std::string const& bin, std::vector<std::string> const& args);
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);
#endif //UTIL_HPP #endif //UTIL_HPP

BIN
lxsh

Binary file not shown.

View file

@ -6,6 +6,8 @@
#include "options.hpp" #include "options.hpp"
#include "parse.hpp" #include "parse.hpp"
#include <unistd.h>
std::vector<std::string> included; std::vector<std::string> included;
bool is_sub_special_cmd(std::string in) bool is_sub_special_cmd(std::string in)
@ -99,10 +101,24 @@ std::string concatargs(std::vector<std::string> args)
std::string generate_resolve(std::vector<std::string> args, int ind) std::string generate_resolve(std::vector<std::string> args, int ind)
{ {
std::string ret;
auto opts=create_resolve_opts(); auto opts=create_resolve_opts();
auto rargs = opts.process(args, false, true, false); auto rargs = opts.process(args, false, true, false);
std::string cmd=concatargs(rargs); std::string cmd=concatargs(rargs);
std::string dir;
if(!opts['C'] && !piped)
{
dir=pwd();
std::string cddir=ztd::exec("dirname", g_origin).first;
cddir.pop_back();
chdir(cddir.c_str());
}
// exec call
auto p=ztd::shp("exec "+cmd); auto p=ztd::shp("exec "+cmd);
if(!opts['f'] && p.second!=0) if(!opts['f'] && p.second!=0)
@ -114,17 +130,29 @@ std::string generate_resolve(std::vector<std::string> args, int ind)
if(opts['p']) if(opts['p'])
{ {
block bl = parse(p.first); block bl;
std::string ret = bl.generate(ind, false); try
{
bl = parse(p.first);
}
catch(ztd::format_error& e)
{
throw ztd::format_error(e.what(), "command `"+cmd+'`', e.data(), e.where());
}
ret = bl.generate(ind, false);
std::string tmpind=INDENT; std::string tmpind=INDENT;
ret = ret.substr(tmpind.size()); ret = ret.substr(tmpind.size());
ret.pop_back(); // remove \n ret.pop_back(); // remove \n
return ret;
} }
else else
{ {
return p.first; ret = p.first;
} }
if(!opts['C'] && !piped)
chdir(dir.c_str());
return ret;
} }
std::string generate_include(std::vector<std::string> args, int ind) std::string generate_include(std::vector<std::string> args, int ind)
@ -140,6 +168,17 @@ std::string generate_include(std::vector<std::string> args, int ind)
else if(opts['d']) else if(opts['d'])
quote = '"'; quote = '"';
std::string curfile=g_origin;
std::string dir;
if(!opts['C'] && !piped)
{
dir=pwd();
std::string cddir=ztd::exec("dirname", curfile).first;
cddir.pop_back();
chdir(cddir.c_str());
}
// do shell resolution // do shell resolution
std::string command="for I in "; std::string command="for I in ";
for(auto it: rargs) for(auto it: rargs)
@ -149,6 +188,7 @@ std::string generate_include(std::vector<std::string> args, int ind)
auto v = split(inc, '\n'); auto v = split(inc, '\n');
std::string file; std::string file;
block bl; block bl;
bool indent_remove=true; bool indent_remove=true;
@ -159,10 +199,13 @@ std::string generate_include(std::vector<std::string> args, int ind)
add_include(it) ) // not already included add_include(it) ) // not already included
{ {
file=import_file(it); file=import_file(it);
if(opts['e'])
file = stringReplace(file, "\"", "\\\"");
if(opts['r']) if(opts['r'])
ret += file; ret += file;
else else
{ {
g_origin=it;
try try
{ {
bl = parse(quote + file + quote); bl = parse(quote + file + quote);
@ -182,6 +225,9 @@ std::string generate_include(std::vector<std::string> args, int ind)
} }
} }
} }
if(!opts['C'] && !piped)
chdir(dir.c_str());
g_origin=curfile;
if(!opts['r']) if(!opts['r'])
ret.pop_back(); ret.pop_back();
@ -215,13 +261,17 @@ std::string block::generate_case(int ind)
ind++; ind++;
for(auto cs: this->cases) for(auto cs: this->cases)
{ {
// case definition : foo)
if(!opt_minimize) ret += INDENT; if(!opt_minimize) ret += INDENT;
ret += cs.first.generate(ind) + ')'; ret += cs.first.generate(ind) + ')';
if(!opt_minimize) ret += '\n'; if(!opt_minimize) ret += '\n';
// commands
for(auto it: cs.second) for(auto it: cs.second)
ret += it.generate(ind+1); ret += it.generate(ind+1);
// end of case: ;;
if(opt_minimize) if(opt_minimize)
{ {
// ;; can be right after command
if(ret[ret.size()-1] == '\n') if(ret[ret.size()-1] == '\n')
ret.pop_back(); ret.pop_back();
} }
@ -233,6 +283,7 @@ std::string block::generate_case(int ind)
} }
ret += ";;\n"; ret += ";;\n";
} }
// close case
ind--; ind--;
if(!opt_minimize) ret += INDENT; if(!opt_minimize) ret += INDENT;
ret += "esac"; ret += "esac";
@ -251,25 +302,30 @@ std::string block::generate(int ind, bool print_shebang)
{ {
if(type==function) if(type==function)
{ {
// function definition
ret += shebang + "()"; ret += shebang + "()";
if(!opt_minimize) ret += '\n' + INDENT; if(!opt_minimize) ret += '\n' + INDENT;
ret += "{\n"; ret += "{\n";
// commands
for(auto it: cls) for(auto it: cls)
ret += it.generate(ind+1); ret += it.generate(ind+1);
if(!opt_minimize) if(!opt_minimize) ret += INDENT;
ret += INDENT; // end function
ret += '}'; ret += '}';
} }
else if(type==subshell) else if(type==subshell)
{ {
// open subshell
ret += '('; ret += '(';
if(!opt_minimize) ret += '\n'; if(!opt_minimize) ret += '\n';
// commands
for(auto it: cls) for(auto it: cls)
ret += it.generate(ind+1); ret += it.generate(ind+1);
if(opt_minimize) if(opt_minimize)
ret.pop_back(); ret.pop_back(); // ) can be right after command
else else
ret += INDENT; ret += INDENT;
// close subshell
ret += ')'; ret += ')';
} }
else if(type==brace) else if(type==brace)

View file

@ -7,18 +7,19 @@
#include <unistd.h> #include <unistd.h>
#include "util.hpp"
#include "struc.hpp" #include "struc.hpp"
#include "parse.hpp" #include "parse.hpp"
#include "options.hpp" #include "options.hpp"
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
auto args=options.process(argc, argv); auto args=options.process(argc, argv, false, true);
if(options['m']) if(options['m'])
opt_minimize=true; opt_minimize=true;
bool piped=false; piped=false;
if(options['h']) if(options['h'])
{ {
@ -58,34 +59,48 @@ int main(int argc, char* argv[])
} }
} }
if(!piped && !options['C'])
{
std::string dir=ztd::exec("dirname", file).first;
dir.pop_back();
file=ztd::exec("basename", file).first;
file.pop_back();
chdir(dir.c_str());
}
g_origin=file; g_origin=file;
add_include(file); add_include(file);
if(args.size()>0) try
{ {
try block sh(parse(import_file(file)));
if(options['E'])
{
std::string data=sh.generate();
// generate path
std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ;
std::string filepath = tmpdir + "/lxsh_exec_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10");
// create stream
std::ofstream stream(filepath);
if(!stream)
throw std::runtime_error("Failed to write to file '"+filepath+'\'');
// output
stream << data;
stream.close();
auto p = ztd::exec("chmod", "+x", filepath);
if(p.second != 0)
return p.second;
args.erase(args.begin());
_exec(filepath, args);
}
else
{ {
block sh(parse(import_file(file)));
std::cout << sh.generate(); std::cout << sh.generate();
} }
catch(ztd::format_error& e)
{
printFormatException(e);
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
} }
catch(ztd::format_error& e)
{
printFormatException(e);
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0; return 0;
} }

View file

@ -2,13 +2,15 @@
ztd::option_set options = gen_options(); ztd::option_set options = gen_options();
bool opt_minimize; bool opt_minimize;
bool piped=false;
ztd::option_set gen_options() ztd::option_set gen_options()
{ {
ztd::option_set ret; ztd::option_set ret;
ret.add(ztd::option('h', "help", false, "Display this help message")); ret.add(ztd::option('h', "help", false, "Display this help message"));
ret.add(ztd::option('m', "minimize", false, "Minimize code")); ret.add(ztd::option('m', "minimize", false, "Minimize code"));
ret.add(ztd::option('C', "no-cd", false, "Don't change directories")); ret.add(ztd::option('E', "exec", false, "Directly exec instead of outputting"));
ret.add(ztd::option("help-commands", false, "Print help for linker commands")); ret.add(ztd::option("help-commands", false, "Print help for linker commands"));
return ret; return ret;
} }
@ -19,8 +21,9 @@ ztd::option_set create_include_opts()
opts.add( opts.add(
ztd::option('s', false, "Single quote contents"), ztd::option('s', false, "Single quote contents"),
ztd::option('d', false, "Double quote contents"), ztd::option('d', false, "Double quote contents"),
// ztd::option('e', false, "Escape for double quotes"), ztd::option('e', false, "Escape double quotes"),
ztd::option('r', false, "Include raw contents, don't parse"), ztd::option('r', false, "Include raw contents, don't parse"),
ztd::option('C', false, "Don't cd to folder the file is in"),
ztd::option('f', false, "Force include even if already included. Don't count as included") ztd::option('f', false, "Force include even if already included. Don't count as included")
); );
return opts; return opts;
@ -30,8 +33,8 @@ ztd::option_set create_resolve_opts()
{ {
ztd::option_set opts; ztd::option_set opts;
opts.add( opts.add(
// ztd::option('e', false, "Escape for double quotes"),
ztd::option('p', false, "Parse contents as shell code"), ztd::option('p', false, "Parse contents as shell code"),
ztd::option('C', false, "Don't cd to folder this file is in"),
ztd::option('f', false, "Ignore non-zero return values") ztd::option('f', false, "Ignore non-zero return values")
); );
return opts; return opts;
@ -39,7 +42,7 @@ ztd::option_set create_resolve_opts()
void print_help(const char* arg0) void print_help(const char* arg0)
{ {
printf("%s [options] [file]\n", arg0); printf("%s [options] <file> [arg...]\n", arg0);
printf("Link extended shell, allows file including and command resolving\n"); printf("Link extended shell, allows file including and command resolving\n");
printf("See --help-commands for help on linker commands\n"); printf("See --help-commands for help on linker commands\n");
printf("\n"); printf("\n");
@ -50,7 +53,7 @@ void print_help(const char* arg0)
void print_include_help() void print_include_help()
{ {
printf("%%include [options] <file...>\n"); printf("%%include [options] <file...>\n");
printf("Include the targeted files. Paths are relative to folder of current file\n"); printf("Include the targeted files, from folder of current file\n");
printf(" - Regular shell processing applies to the file arguments\n"); printf(" - Regular shell processing applies to the file arguments\n");
printf(" - Only includes not already included files\n"); printf(" - Only includes not already included files\n");
printf(" - `%%include` in command substitutions replaces the substitution\n"); printf(" - `%%include` in command substitutions replaces the substitution\n");
@ -64,7 +67,7 @@ void print_include_help()
void print_resolve_help() void print_resolve_help()
{ {
printf("%%resolve [options] <command...>\n"); printf("%%resolve [options] <command...>\n");
printf("Execute shell command and substitute output. Paths is from folder of current file\n"); printf("Execute shell command and substitute output, from folder of current file\n");
printf(" - Fails if return value is not 0. Can be ignored with -f\n"); printf(" - Fails if return value is not 0. Can be ignored with -f\n");
printf(" - `%%resolve` in command substitutions replaces the substitution\n"); printf(" - `%%resolve` in command substitutions replaces the substitution\n");
printf(" =>`%%resolve_s` can be used inside a substitution to prevent this\n"); printf(" =>`%%resolve_s` can be used inside a substitution to prevent this\n");

View file

@ -241,7 +241,9 @@ std::pair<condlist, uint32_t> parse_condlist(const char* in, uint32_t size, uint
return std::make_pair(ret, i); return std::make_pair(ret, i);
} }
// parse condlists until ) // parse a subshell
// must start right after the opening (
// ends at ) and nothing else
std::pair<block, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_t start) std::pair<block, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_t start)
{ {
uint32_t i = skip_unread(in, size, start); uint32_t i = skip_unread(in, size, start);
@ -258,7 +260,9 @@ std::pair<block, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_
return std::make_pair(ret,i); return std::make_pair(ret,i);
} }
// parse condlists until } // parse a brace block
// must start right after the opening {
// ends at } and nothing else
std::pair<block, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t start) std::pair<block, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t start)
{ {
uint32_t i = skip_unread(in, size, start); uint32_t i = skip_unread(in, size, start);
@ -279,6 +283,9 @@ std::pair<block, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t s
return std::make_pair(ret,i); return std::make_pair(ret,i);
} }
// parse a functions
// must start right after the ()
// then parses a brace block
std::pair<block, uint32_t> parse_function(const char* in, uint32_t size, uint32_t start) std::pair<block, uint32_t> parse_function(const char* in, uint32_t size, uint32_t start)
{ {
block ret(block::function); block ret(block::function);
@ -301,16 +308,18 @@ std::pair<block, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t sta
block ret(block::cmd); block ret(block::cmd);
uint32_t i=start; uint32_t i=start;
// parse first arg and keep it
auto tp=parse_arg(in, size, i); auto tp=parse_arg(in, size, i);
i=skip_unread(in, size, tp.second); i=skip_unread(in, size, tp.second);
if(word_eq("()", in, size, i)) if(word_eq("()", in, size, i)) // is a function
{ {
i += 2; i += 2;
auto pp = parse_function(in, size, i); auto pp = parse_function(in, size, i);
// first arg is function name
pp.first.shebang = tp.first.raw; pp.first.shebang = tp.first.raw;
return pp; return pp;
} }
else else // is a command
{ {
auto pp=parse_arglist(in, size, start); auto pp=parse_arglist(in, size, start);
ret.args = pp.first; ret.args = pp.first;
@ -320,16 +329,20 @@ std::pair<block, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t sta
return std::make_pair(ret, i); return std::make_pair(ret, i);
} }
// parse a case block
// must start right after the case
// ends at } and nothing else
std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start) std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start)
{ {
block ret(block::case_block); block ret(block::case_block);
uint32_t i=start; uint32_t i=skip_unread(in, size, start);;
auto pa = parse_arg(in, size, i); // case arg // get the treated argument
auto pa = parse_arg(in, size, i);
ret.carg = pa.first; ret.carg = pa.first;
i=skip_unread(in, size, pa.second); i=skip_unread(in, size, pa.second);
// must be an 'in'
if(!word_eq("in", in, size, i)) if(!word_eq("in", in, size, i))
{ {
auto pp=parse_arg(in, size, i); auto pp=parse_arg(in, size, i);
@ -338,6 +351,7 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
i=skip_unread(in, size, i+2); i=skip_unread(in, size, i+2);
// parse all cases
while(i<size && !word_eq("esac", in, size, i, " \t\n;()&") ) while(i<size && !word_eq("esac", in, size, i, " \t\n;()&") )
{ {
// toto) // toto)
@ -361,18 +375,21 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
if(in[i] == ')') if(in[i] == ')')
throw ztd::format_error( strf("Unexpected token '%c', expecting ';;'", in[i]), g_origin, in, i ); throw ztd::format_error( strf("Unexpected token '%c', expecting ';;'", in[i]), g_origin, in, i );
// end of case: on same line
if(in[i-1] == ';' && in[i] == ';') if(in[i-1] == ';' && in[i] == ';')
{ {
i++; i++;
break; break;
} }
// end of case: on new line
i=skip_unread(in, size, i); i=skip_unread(in, size, i);
if(word_eq(";;", in, size, i)) if(word_eq(";;", in, size, i))
{ {
i+=2; i+=2;
break; break;
} }
// end of block: ignore missing ;;
if(word_eq("esac", in, size, i)) if(word_eq("esac", in, size, i))
break; break;
@ -381,6 +398,7 @@ std::pair<block, uint32_t> parse_case(const char* in, uint32_t size, uint32_t st
ret.cases.push_back(cc); ret.cases.push_back(cc);
} }
// ended before finding esac
if(i>=size) if(i>=size)
throw ztd::format_error("Expecting 'esac'", g_origin, in, i); throw ztd::format_error("Expecting 'esac'", g_origin, in, i);
i+=4; i+=4;
@ -405,8 +423,7 @@ std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t s
} }
else if(word_eq("case", in, size, i)) else if(word_eq("case", in, size, i))
{ {
i = skip_unread(in, size, i+4); ret = parse_case(in, size, i+4);
ret = parse_case(in, size, i);
} }
else // command else // command
{ {
@ -424,15 +441,16 @@ std::pair<block, uint32_t> parse_block(const char* in, uint32_t size, uint32_t s
// parse main // parse main
block parse(const char* in, uint32_t size) block parse(const char* in, uint32_t size)
{ {
block ret(block::main); block ret(block::main);
uint32_t i=0; uint32_t i=0;
// get shebang
if(word_eq("#!", in, size, 0)) if(word_eq("#!", in, size, 0))
{ {
i=skip_until(in, size, 0, "\n"); i=skip_until(in, size, 0, "\n");
ret.shebang=std::string(in, i); ret.shebang=std::string(in, i);
} }
i = skip_unread(in, size, i); i = skip_unread(in, size, i);
// parse all commands
while(i<size) while(i<size)
{ {
auto pp=parse_condlist(in, size, i); auto pp=parse_condlist(in, size, i);
@ -442,6 +460,7 @@ block parse(const char* in, uint32_t size)
return ret; return ret;
} }
// import a file's contents into a string
std::string import_file(std::string const& path) std::string import_file(std::string const& path)
{ {
std::ifstream st(path); std::ifstream st(path);

View file

@ -2,6 +2,8 @@
#include "util.hpp" #include "util.hpp"
#include <unistd.h>
block make_cmd(std::vector<std::string> args) block make_cmd(std::vector<std::string> args)
{ {
block cmd(block::cmd); block cmd(block::cmd);
@ -24,6 +26,7 @@ void arg::setstring(std::string const& str)
{ {
sa.resize(0); sa.resize(0);
sa.push_back(subarg(str)); sa.push_back(subarg(str));
raw = str;
} }
void condlist::add(pipeline const& pl, bool or_op) void condlist::add(pipeline const& pl, bool or_op)

View file

@ -1,5 +1,9 @@
#include "util.hpp" #include "util.hpp"
#include <unistd.h>
#include <ztd/shell.hpp>
std::string indenting_string="\t"; std::string indenting_string="\t";
std::string indent(int n) std::string indent(int n)
@ -52,3 +56,36 @@ std::string delete_brackets(std::string const& in)
} }
return ret; return ret;
} }
std::string pwd()
{
char buf[2048];
if(getcwd(buf, 2048) != NULL)
{
std::string ret=ztd::exec("pwd").first; // getcwd failed: call pwd
ret.pop_back();
return ret;
}
return std::string(buf);
}
void _exec(std::string const& bin, std::vector<std::string> const& args)
{
std::vector<char*> rargs;
rargs.push_back((char*) bin.c_str());
for(auto it=args.begin(); it!=args.end(); it++)
rargs.push_back((char*) it->c_str());
rargs.push_back(NULL);
execvp(bin.c_str(), rargs.data());
}
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace)
{
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos)
{
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}