Major rework

+ Move to pointers internally (performance improvement)
+ Polymorphic internal classes (performance improvement)
+ Add if/for/while parsing
This commit is contained in:
zawz 2020-10-20 14:41:59 +02:00
parent fd19eab3db
commit 6350e1cfef
7 changed files with 1457 additions and 593 deletions

View file

@ -11,7 +11,7 @@ extern std::string g_origin;
std::string import_file(std::string const& path);
block parse(const char* in, uint32_t size);
inline block parse(std::string const& in) { return parse(in.c_str(), in.size()); }
shmain* parse(const char* in, uint32_t size);
inline shmain* parse(std::string const& in) { return parse(in.c_str(), in.size()); }
#endif //PARSE_HPP

View file

@ -3,7 +3,6 @@
#include <string>
#include <vector>
#include <set>
#include <exception>
#include <stdexcept>
@ -12,18 +11,37 @@
structure:
list_t : condlist[]
arglist_t : arg[]
block:
- group
- brace: list_t
- subsh: list_t
- cmd: arglist[]
block: can be one of
- main
string (shebang)
list_t (commands)
- brace
list_t
- subshell
list_t
- cmd: arglist
- case
- arg (input)
- pair<arg,list_t>[] (cases)
arg (input)
pair<arglist_t,list_t>[] (cases)
- if
pair<list_t,list_t>[] (blocks)
list_t (else)
- for
string (variable name)
arglist (iterations)
list_t (execution)
- while
list_t (condition)
list_t (execution)
condlist:
pipeline[]
or_ops[]
> always one smaller than pipeline
> designates an OR if true, otherwise an AND
pipeline:
block[]
@ -31,13 +49,15 @@ pipeline:
arglist:
arg[]
arg:
- raw
- subarg[] split into subarguments in case of subshells
arg: has
raw
subarg[] can have multiple subarguments if string and subshells
subarg:
- raw
subarg: can be one of
- string
- block: subshell (substitution)
- arithmetic
*/
#define AND_OP false
@ -48,26 +68,42 @@ class block;
class pipeline;
class arg;
class subarg;
class cmd;
// type pack of condlist
typedef std::vector<condlist> list_t;
typedef std::vector<condlist*> list_t;
typedef std::vector<arg*> arglist_t;
block make_cmd(std::vector<std::string> args);
cmd* make_cmd(std::vector<std::string> args);
bool add_include(std::string const& file);
// meta subarg type
class subarg
{
public:
// type
enum argtype { s_string, s_subshell, s_arithmetic };
argtype type;
virtual ~subarg() {;}
std::string generate(int ind);
};
class arg
{
public:
arg() { ; }
arg(std::string const& str) {this->setstring(str);}
~arg() { for(auto it: sa) delete it; }
void setstring(std::string const& str);
// has to be set manually
std::string raw;
std::vector<subarg> sa;
std::vector<subarg*> sa;
// return if is a string and only one subarg
std::string string();
@ -75,111 +111,283 @@ public:
std::string generate(int ind);
};
// arglist
class arglist
{
public:
inline void add(arg const& in) { args.push_back(in); }
inline void push_back(arg const& in) { args.push_back(in); }
~arglist() { for( auto it: args ) delete it; }
inline void add(arg* in) { args.push_back(in); }
inline void push_back(arg* in) { args.push_back(in); }
std::vector<arg> args;
arglist_t args;
std::vector<std::string> strargs(uint32_t start);
inline uint64_t size() { return args.size(); }
inline arg& operator[](uint32_t i) { return args[i]; }
inline arg* operator[](uint32_t i) { return args[i]; }
std::string generate(int ind);
};
class redir
{
public:
enum redirtype { none, write, append, read, raw } ;
redir(redirtype in=none) { type=in; }
redirtype type;
arg val;
};
class block
{
public:
// type
enum blocktype { none, subshell, brace, main, cmd, function, case_block, for_block, if_block, while_block};
blocktype type;
// ctor
block() { type=none; }
block(blocktype in) { type=in; }
// subshell/brace/main
list_t cls;
// cmd
arglist args;
// case
arg carg;
std::vector< std::pair<std::vector<arg>, list_t> > cases;
// main: shebang
// function: name
std::string shebang;
// subshell: return the containing cmd, if it is a single command
block* single_cmd();
std::string generate(int ind=0, bool print_shebang=true);
private:
std::string generate_cmd(int ind);
std::string generate_case(int ind);
};
// PL
class pipeline
{
public:
pipeline() {;}
pipeline(block const& bl) { cmds.push_back(bl); }
inline void add(block bl) { this->cmds.push_back(bl); }
std::vector<block> cmds;
pipeline() { negated=false; }
pipeline(block* bl) { cmds.push_back(bl); negated=false; }
inline void add(block* bl) { this->cmds.push_back(bl); }
std::vector<block*> cmds;
bool negated; // negated return value (! at start)
std::string generate(int ind);
};
// CL
class condlist
{
public:
condlist() { parallel=false; }
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(new pipeline(pl));}
condlist(pipeline* pl) { parallel=false; this->add(pl);}
bool parallel; // & at the end
void add(pipeline const& pl, bool or_op=false);
void add(pipeline* 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
void negate();
std::string generate(int ind, bool pre_indent=true);
};
// class redir
// {
// public:
// enum redirtype { none, write, append, read, raw } ;
// redir(redirtype in=none) { type=in; }
// redirtype type;
// arg val;
// };
class cmd;
// Meta block
class block
{
public:
// type
enum blocktype { block_subshell, block_brace, block_main, block_cmd, block_function, block_case, block_if, block_for, block_while, block_until };
blocktype type;
// ctor
block() { redirs=nullptr; }
virtual ~block() { if(redirs!=nullptr) delete redirs; }
// cmd
arglist* redirs;
// subshell: return the containing cmd, if it is a single command
cmd* single_cmd();
std::string generate_redirs(int ind);
virtual std::string generate(int ind)=0;
};
// block types
class subshell : public block
{
public:
subshell() { type=block::block_subshell; }
~subshell() { for(auto it: cls) delete it; }
cmd* single_cmd();
list_t cls;
std::string generate(int ind);
};
class brace : public block
{
public:
brace() { type=block::block_brace; }
~brace() {
if(redirs!=nullptr) delete redirs;
for(auto it: cls) delete it; }
cmd* single_cmd();
list_t cls;
std::string generate(int ind);
};
class subarg
class shmain : public block
{
public:
// type
enum argtype { string, subshell, arithmetic };
argtype type;
shmain() { type=block::block_main; }
~shmain() {
if(redirs!=nullptr) delete redirs;
for(auto it: cls) delete it; }
// ctor
subarg(argtype in) { this->type=in; }
subarg(std::string const& in="") { type=string; val=in; }
subarg(block const& in) { type=subshell; sbsh=in; }
std::string shebang;
list_t cls;
std::string generate(bool print_shebang=true, int ind=0);
std::string generate(int ind);
};
class function : public block
{
public:
function() { type=block::block_function; }
~function() {
if(redirs!=nullptr) delete redirs;
for(auto it: cls) delete it; }
std::string name;
list_t cls;
std::string generate(int ind);
};
class cmd : public block
{
public:
cmd(arglist* in=nullptr) { type=block::block_cmd; args=in; }
~cmd() {
if(redirs!=nullptr) delete redirs;
if(args!=nullptr) delete args; }
static const std::string empty_string;
std::string const& firstarg_raw();
arglist* args;
std::string generate(int ind);
};
class case_block : public block
{
public:
case_block(arg* in=nullptr) { type=block::block_case; carg=in; }
~case_block() {
if(redirs!=nullptr) delete redirs;
if(carg!=nullptr) delete carg;
for( auto cit : cases )
{
for( auto ait : cit.first )
delete ait;
for( auto lit : cit.second )
delete lit;
}
}
arg* carg;
std::vector< std::pair<arglist_t, list_t> > cases;
std::string generate(int ind);
};
class if_block : public block
{
public:
if_block() { type=block::block_if; }
~if_block() {
if(redirs!=nullptr) delete redirs;
for(auto it: else_cls) delete it;
for(auto ifb: blocks)
{
for(auto it: ifb.first)
delete it;
for(auto it: ifb.second)
delete it;
}
}
std::vector< std::pair<list_t,list_t> > blocks;
list_t else_cls;
std::string generate(int ind);
};
class for_block : public block
{
public:
for_block(std::string const& name="", arglist* args=nullptr) { type=block::block_for; varname=name; iter=args; }
~for_block() {
if(redirs!=nullptr) delete redirs;
if(iter!=nullptr) delete iter;
for(auto it: ops) delete it;
}
std::string varname;
arglist* iter;
list_t ops;
std::string generate(int ind);
};
class while_block : public block
{
public:
while_block() { type=block::block_while; }
~while_block() {
if(redirs!=nullptr) delete redirs;
for(auto it: cond) delete it;
for(auto it: ops) delete it;
}
condlist* real_condition() { return *(cond.end()-1); }
list_t cond;
list_t ops;
std::string generate(int ind);
};
// Subarg subtypes
class subarg_string : public subarg
{
public:
subarg_string(std::string const& in="") { type=subarg::s_string; val=in; }
// raw string
std::string val;
// subshell
block sbsh;
std::string generate(int ind) { return val; }
};
class subarg_arithmetic : public subarg
{
public:
subarg_arithmetic() { type=subarg::s_arithmetic; }
std::string val;
std::string generate(int ind) { return "$(("+val+"))"; }
};
class subarg_subshell : public subarg
{
public:
subarg_subshell(subshell* in=nullptr) { type=subarg::s_subshell; sbsh=in; }
subarg_subshell(subshell in) { type=subarg::s_subshell; sbsh=new subshell(in); }
~subarg_subshell() { if(sbsh != nullptr) delete sbsh;}
subshell* sbsh;
std::string generate(int ind);
};

View file

@ -15,12 +15,20 @@ bool is_sub_special_cmd(std::string in)
return in == "%include_sub" || in == "%resolve_sub";
}
std::string indented(std::string const& in, uint32_t ind)
{
if(!opt_minimize)
return indent(ind) + in;
else
return in;
}
std::string arg::generate(int ind)
{
std::string ret;
for(auto it: sa)
{
ret += it.generate(ind);
ret += it->generate(ind);
}
return ret;
}
@ -31,7 +39,7 @@ std::string arglist::generate(int ind)
for(auto it: args)
{
ret += it.generate(ind);
ret += it->generate(ind);
ret += ' ';
}
@ -47,31 +55,33 @@ std::string pipeline::generate(int ind)
if(cmds.size()<=0)
return "";
ret += cmds[0].generate(ind);
if(negated)
ret += "! ";
ret += cmds[0]->generate(ind);
for(uint32_t i=1 ; i<cmds.size() ; i++)
{
ret += opt_minimize ? "|" : " | " ;
ret += cmds[i].generate(ind);
ret += cmds[i]->generate(ind);
}
return ret;
}
std::string condlist::generate(int ind)
std::string condlist::generate(int ind, bool pre_indent)
{
std::string ret;
if(pls.size() <= 0)
return "";
if(!opt_minimize)
ret += INDENT;
ret += pls[0].generate(ind);
if(pre_indent)
ret += indented("", ind);
ret += pls[0]->generate(ind);
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
{
if(or_ops[i])
ret += opt_minimize ? "||" : " || ";
else
ret += opt_minimize ? "&&" : " && ";
ret += pls[i+1].generate(ind);
ret += pls[i+1]->generate(ind);
}
if(ret=="")
return "";
@ -136,18 +146,18 @@ std::string generate_resolve(std::vector<std::string> args, int ind)
if(opts['p'])
{
block bl;
shmain* sh;
try
{
bl = parse(p.first);
sh = 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;
ret = ret.substr(tmpind.size());
ret = sh->generate(false, ind);
delete sh;
ret = ret.substr(indent(ind).size());
ret.pop_back(); // remove \n
}
else
@ -198,7 +208,7 @@ std::string generate_include(std::vector<std::string> args, int ind)
std::string file;
block bl;
shmain* bl=nullptr;
bool indent_remove=true;
for(auto it : v)
@ -224,12 +234,12 @@ std::string generate_include(std::vector<std::string> args, int ind)
{
throw ztd::format_error(e.what(), it, e.data(), e.where());
}
file = bl.generate(ind, false);
file = bl->generate(false, ind);
delete bl;
if(indent_remove)
{
indent_remove=false;
std::string tmpind=INDENT;
file = file.substr(tmpind.size());
file = file.substr(indent(ind).size());
}
ret += file;
}
@ -246,161 +256,253 @@ std::string generate_include(std::vector<std::string> args, int ind)
return ret;
}
std::string block::generate_cmd(int ind)
// BLOCK
std::string block::generate_redirs(int ind)
{
std::string ret;
if(args.size()<=0)
return "";
std::string cmd=args[0].raw;
if(cmd == "%include" || cmd == "%include_s")
if(redirs != nullptr)
{
ret += generate_include(args.strargs(1), ind);
}
else if(cmd == "%resolve" || cmd == "%resolve_s")
{
ret += generate_resolve(args.strargs(1), ind);
}
else
ret = args.generate(ind);
return ret;
}
std::string block::generate_case(int ind)
{
std::string ret;
ret += "case " + carg.generate(ind) + " in\n";
ind++;
for(auto cs: this->cases)
{
// case definition : foo)
if(!opt_minimize) ret += INDENT;
for(auto it: cs.first)
ret += it.generate(ind) + '|';
ret.pop_back();
ret += ')';
if(!opt_minimize) ret += '\n';
// commands
for(auto it: cs.second)
ret += it.generate(ind+1);
// end of case: ;;
if(opt_minimize)
{
// ;; can be right after command
if(ret[ret.size()-1] == '\n')
ret.pop_back();
}
else
{
ind++;
ret += INDENT;
ind--;
}
ret += ";;\n";
}
// close case
ind--;
if(!opt_minimize) ret += INDENT;
ret += "esac";
return ret;
}
std::string block::generate(int ind, bool print_shebang)
{
std::string ret;
if(type==cmd)
{
ret += generate_cmd(ind);
}
else
{
if(type==function)
{
// function definition
ret += shebang + "()";
if(!opt_minimize) ret += '\n' + INDENT;
ret += "{\n";
// commands
for(auto it: cls)
ret += it.generate(ind+1);
if(!opt_minimize) ret += INDENT;
// end function
ret += '}';
}
else if(type==subshell)
{
// open subshell
ret += '(';
if(!opt_minimize) ret += '\n';
// commands
for(auto it: cls)
ret += it.generate(ind+1);
if(opt_minimize && ret.size()>1)
ret.pop_back(); // ) can be right after command
else
ret += INDENT;
// close subshell
ret += ')';
}
else if(type==brace)
{
ret += "{\n" ;
for(auto it: cls)
ret += it.generate(ind+1);
if(!opt_minimize)
ret += INDENT;
ret += '}';
}
else if(type==main)
{
if(print_shebang && shebang!="")
ret += shebang + '\n';
for(auto it: cls)
ret += it.generate(ind);
}
else if(type==case_block)
{
ret += generate_case(ind);
}
std::string t = generate_cmd(ind); // leftover redirections
std::string t = redirs->generate(ind);
if(t!="")
{
if(!opt_minimize) ret += ' ';
ret += t;
}
}
return ret;
}
std::string if_block::generate(int ind)
{
std::string ret;
for(uint32_t i=0; i<blocks.size(); i++ )
{
// condition
if(i==0)
ret += "if ";
else
ret += "elif ";
// first cmd: on same line with no indent
ret += blocks[i].first[0]->generate(ind+1, false);
// other cmds: on new lines
for(uint32_t j=1; j<blocks[i].first.size(); j++ )
ret += blocks[i].first[j]->generate(ind+1);
// execution
ret += indented("then\n", ind);
for(auto it: blocks[i].second)
ret += it->generate(ind+1);
}
if(else_cls.size()>0)
{
ret += indented("else\n", ind);
for(auto it: else_cls)
ret += it->generate(ind+1);
}
ret += indented("fi", ind);
return ret;
}
std::string for_block::generate(int ind)
{
std::string ret;
ret += "for "+varname;
if(iter != nullptr)
ret += " in " + iter->generate(ind);
ret += '\n';
ret += indented("do\n", ind);
for(auto it: ops)
ret += it->generate(ind+1);
ret += indented("done", ind);
return ret;
}
std::string while_block::generate(int ind)
{
std::string ret;
ret += "while";
if(cond.size() == 1)
{
ret += " " + cond[0]->generate(ind+1, false);
}
else
{
ret += '\n';
for(auto it: cond)
ret += it->generate(ind+1);
}
ret += indented("do\n", ind);
for(auto it: ops)
ret += it->generate(ind+1);
ret += indented("done", ind);
return ret;
}
std::string subshell::generate(int ind)
{
std::string ret;
// open subshell
ret += '(';
if(!opt_minimize) ret += '\n';
// commands
for(auto it: cls)
ret += it->generate(ind+1);
if(opt_minimize && ret.size()>1)
ret.pop_back(); // ) can be right after command
// close subshell
ret += indented(")", ind);
ret += generate_redirs(ind);
return ret;
}
std::string shmain::generate(int ind)
{
return this->generate(false, ind);
}
std::string shmain::generate(bool print_shebang, int ind)
{
std::string ret;
if(print_shebang && shebang!="")
ret += shebang + '\n';
for(auto it: cls)
ret += it->generate(ind);
return ret;
}
std::string brace::generate(int ind)
{
std::string ret;
ret += "{\n" ;
for(auto it: cls)
ret += it->generate(ind+1);
ret += indented("}", ind);
ret += generate_redirs(ind);
return ret;
}
std::string function::generate(int ind)
{
std::string ret;
// function definition
ret += name + "()";
if(!opt_minimize) ret += '\n' + indent(ind);
ret += "{\n";
// commands
for(auto it: cls)
ret += it->generate(ind+1);
ret += indented("}", ind);
ret += generate_redirs(ind);
return ret;
}
std::string case_block::generate(int ind)
{
std::string ret;
ret += "case " + carg->generate(ind) + " in\n";
ind++;
for(auto cs: this->cases)
{
// case definition : foo)
ret += indented("", ind);
// args
for(auto it: cs.first)
ret += it->generate(ind) + '|';
ret.pop_back();
ret += ')';
if(!opt_minimize) ret += '\n';
// commands
for(auto it: cs.second)
ret += it->generate(ind+1);
// end of case: ;;
if(opt_minimize && ret[ret.size()-1] == '\n') // ;; can be right after command
{
ret.pop_back();
}
ret += indented(";;\n", ind+1);
}
// close case
ind--;
ret += indented("esac", ind);
ret += generate_redirs(ind);
return ret;
}
std::string cmd::generate(int ind)
{
std::string ret;
if(args==nullptr || args->size()<=0)
return "";
std::string cmdname=(*args)[0]->raw;
if(cmdname == "%include" || cmdname == "%include_s")
{
ret += generate_include(args->strargs(1), ind);
}
else if(cmdname == "%resolve" || cmdname == "%resolve_s")
{
ret += generate_resolve(args->strargs(1), ind);
}
else
ret = args->generate(ind);
return ret;
}
// TEMPLATE
// std::string thing::generate(int ind)
// {
// std::string ret;
// return ret;
// }
// SUBARG
std::string subarg::generate(int ind)
{
switch(type)
{
case subarg::s_string:
return dynamic_cast<subarg_string*>(this)->generate(ind);
case subarg::s_arithmetic:
return dynamic_cast<subarg_arithmetic*>(this)->generate(ind);
case subarg::s_subshell:
return dynamic_cast<subarg_subshell*>(this)->generate(ind);
}
// doesn't happen, just to get rid of warning
return "";
}
std::string subarg_subshell::generate(int ind)
{
std::string ret;
if(type == subarg::string)
// includes and resolves inside command substitutions
// resolve here and not inside subshell
cmd* cmd = sbsh->single_cmd();
if( cmd != nullptr && (cmd->firstarg_raw() == "%include" || cmd->firstarg_raw() == "%resolve") )
{
ret += val;
ret += cmd->generate(ind);
}
else if(type == subarg::arithmetic)
// regular substitution
else
{
ret += "$(("+val+"))";
}
else if(type == subarg::subshell)
{
// includes and resolves inside command substitutions
// resolve here and not inside subshell
block* cmd = sbsh.single_cmd();
if( cmd != nullptr && (cmd->args[0].raw == "%include" || cmd->args[0].raw == "%resolve") )
{
ret += cmd->generate(ind);
}
// regular substitution
else
{
ret += '$';
ret += sbsh.generate(ind);
}
ret += '$';
ret += sbsh->generate(ind);
}
return ret;
}

View file

@ -12,9 +12,9 @@
#include "parse.hpp"
#include "options.hpp"
int execute(block& sh, std::vector<std::string>& args)
int execute(shmain* sh, std::vector<std::string>& args)
{
std::string data=sh.generate();
std::string data=sh->generate();
std::string filename=ztd::exec("basename", args[0]).first;
filename.pop_back();
@ -76,10 +76,11 @@ int main(int argc, char* argv[])
return 1;
}
// resolve input
std::string file;
if(args.size() > 0)
if(args.size() > 0) // argument provided
{
if(args[0] == "-")
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
{
piped=true;
file = "/dev/stdin";
@ -89,55 +90,63 @@ int main(int argc, char* argv[])
}
else
{
if(isatty(fileno(stdin)))
if(isatty(fileno(stdin))) // stdin is interactive
{
print_help(argv[0]);
return 1;
}
else
else // is piped
{
piped=true;
file = "/dev/stdin";
}
}
// set origin file
g_origin=file;
add_include(file);
shmain* sh=nullptr;
try
{
block sh(parse(import_file(file)));
// parse
sh = parse(import_file(file));
// resolve shebang
std::string curbin, binshebang;
curbin=ztd::exec("basename", argv[0]).first;
binshebang=ztd::exec("basename", sh.shebang).first;
binshebang=ztd::exec("basename", sh->shebang).first;
if(binshebang==curbin)
sh.shebang="#!/bin/sh";
if(options['e'])
sh->shebang="#!/bin/sh";
// process
if(options['e']) // force exec
{
return execute(sh, args);
}
else if(options['c'])
else if(options['c']) // force console out
{
std::cout << sh.generate();
std::cout << sh->generate();
}
else if(options['o'])
else if(options['o']) // file output
{
std::string destfile=options['o'];
// resolve - to stdout
if(destfile == "-")
destfile = "/dev/stdout";
std::ofstream(destfile) << sh.generate();
ztd::exec("chmod", "+x", destfile);
// output
std::ofstream(destfile) << sh->generate();
// don't chmod on /dev/
if(destfile.substr(0,5) != "/dev/")
ztd::exec("chmod", "+x", destfile);
}
else
else // other process
{
if(binshebang == curbin)
if(binshebang == curbin) // exec if shebang is program
{
return execute(sh, args);
}
else
else // output otherwise
{
std::cout << sh.generate();
std::cout << sh->generate();
}
}
}
@ -151,6 +160,9 @@ int main(int argc, char* argv[])
std::cerr << e.what() << std::endl;
return 2;
}
if(sh!=nullptr)
delete sh;
return 0;

File diff suppressed because it is too large Load diff

View file

@ -4,54 +4,96 @@
#include <unistd.h>
block make_cmd(std::vector<std::string> args)
const std::string cmd::empty_string="";
cmd* make_cmd(std::vector<std::string> args)
{
block cmd(block::cmd);
cmd* ret = new cmd();
ret->args = new arglist();
for(auto it: args)
{
cmd.args.add(arg(it));
ret->args->add(new arg(it));
}
return cmd;
return ret;
}
std::vector<std::string> arglist::strargs(uint32_t start)
{
std::vector<std::string> ret;
for(uint32_t i=start; i<args.size(); i++)
ret.push_back(args[i].raw);
ret.push_back(args[i]->raw);
return ret;
}
void arg::setstring(std::string const& str)
{
for(auto it: sa)
delete it;
sa.resize(0);
sa.push_back(subarg(str));
sa.push_back(new subarg_string(str));
raw = str;
}
void condlist::add(pipeline const& pl, bool or_op)
std::string arg::string()
{
if(sa.size() > 1 || sa[0]->type != subarg::s_string)
return "";
return sa[0]->generate(0);
}
void condlist::add(pipeline* pl, bool or_op)
{
if(this->pls.size() > 0)
this->or_ops.push_back(or_op);
this->pls.push_back(pl);
}
block* block::single_cmd()
cmd* block::single_cmd()
{
if(this->type == block::subshell)
if(this->type == block::block_subshell)
{
if( cls.size() == 1 && // only one condlist
cls[0].pls.size() == 1 && // only one pipeline
cls[0].pls[0].cmds.size() == 1 && // only one block
cls[0].pls[0].cmds[0].type == block::cmd) // block is a command
return &(cls[0].pls[0].cmds[0]); // return command
return dynamic_cast<subshell*>(this)->single_cmd();
}
if(this->type == block::block_brace)
{
return dynamic_cast<brace*>(this)->single_cmd();
}
return nullptr;
}
std::string arg::string()
cmd* subshell::single_cmd()
{
if(sa.size() > 1 || sa[0].type != subarg::string)
return "";
return sa[0].val;
if( cls.size() == 1 && // only one condlist
cls[0]->pls.size() == 1 && // only one pipeline
cls[0]->pls[0]->cmds.size() == 1 && // only one block
cls[0]->pls[0]->cmds[0]->type == block::block_cmd) // block is a command
return dynamic_cast<cmd*>(cls[0]->pls[0]->cmds[0]); // return command
return nullptr;
}
cmd* brace::single_cmd()
{
if( cls.size() == 1 && // only one condlist
cls[0]->pls.size() == 1 && // only one pipeline
cls[0]->pls[0]->cmds.size() == 1 && // only one block
cls[0]->pls[0]->cmds[0]->type == block::block_cmd) // block is a command
return dynamic_cast<cmd*>(cls[0]->pls[0]->cmds[0]); // return command
return nullptr;
}
void condlist::negate()
{
// invert commands
for(uint32_t i=0; i<pls.size(); i++)
pls[i]->negated = !pls[i]->negated;
// invert bool operators
for(uint32_t i=0; i<or_ops.size(); i++)
or_ops[i] = !or_ops[i];
}
std::string const& cmd::firstarg_raw()
{
if(args!=nullptr && args->size()>0)
return args->args[0]->raw;
return cmd::empty_string;
}

View file

@ -4,6 +4,8 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <tuple>
#include <iostream>
#include <ztd/shell.hpp>
@ -120,19 +122,19 @@ std::string stringReplace(std::string subject, const std::string& search, const
return subject;
}
void printFormatError(ztd::format_error const& e, bool print_line)
{
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
}
std::string repeatString(std::string const& str, uint32_t n)
{
std::string ret;
for(uint32_t i=0; i<n; i++)
ret += str;
ret += str;
return ret;
}
void printFormatError(ztd::format_error const& e, bool print_line)
{
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
}
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line)
{
int i=0, j=0; // j: last newline