major changes:
structure: remove manipulation class integrate into variable class debashify: implement debashify on indexed arrays parsing: can now parse manipulations in arithmetics
This commit is contained in:
parent
65083d09b4
commit
fd4c1b0d05
9 changed files with 439 additions and 106 deletions
|
|
@ -47,7 +47,7 @@ std::pair<variable*, uint32_t> parse_var(const char* in, uint32_t size, uint32_t
|
|||
|
||||
// subarg parsers
|
||||
std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<manipulation_subarg*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<variable*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start);
|
||||
// arg parser
|
||||
std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true);
|
||||
// redirect parser
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
|||
{
|
||||
variable* t = dynamic_cast<variable*>(o);
|
||||
recurse(fct, t->index, args...);
|
||||
recurse(fct, t->manip, args...);
|
||||
break;
|
||||
}
|
||||
case _obj::_redirect :
|
||||
|
|
@ -210,13 +211,6 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
|||
recurse(fct, t->sbsh, args...);
|
||||
break;
|
||||
}
|
||||
case _obj::subarg_manipulation :
|
||||
{
|
||||
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(o);
|
||||
recurse(fct, t->var, args...);
|
||||
recurse(fct, t->manip, args...);
|
||||
break;
|
||||
}
|
||||
case _obj::subarg_procsub :
|
||||
{
|
||||
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ subarg: can be one of
|
|||
- subshell (command substitution)
|
||||
- arithmetic
|
||||
- variable
|
||||
- variable manipulation
|
||||
- procsub (bash specific process substitution)
|
||||
> NOTE: MUST be the only subarg in the arg
|
||||
|
||||
|
|
@ -83,7 +82,7 @@ class _obj
|
|||
{
|
||||
public:
|
||||
enum _objtype {
|
||||
subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_manipulation, subarg_procsub,
|
||||
subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_procsub,
|
||||
_variable,
|
||||
_redirect,
|
||||
_arg,
|
||||
|
|
@ -138,6 +137,8 @@ public:
|
|||
|
||||
// return if is a string and only one subarg
|
||||
std::string string();
|
||||
// return if the first subarg is a string
|
||||
std::string first_sa_string();
|
||||
|
||||
inline bool equals(std::string const& in) { return this->string() == in; }
|
||||
|
||||
|
|
@ -147,15 +148,20 @@ public:
|
|||
class variable : public _obj
|
||||
{
|
||||
public:
|
||||
variable(std::string const& in="", arg* i=nullptr, bool def=false) { type=_obj::_variable; varname=in; index=i; definition=def; }
|
||||
variable(std::string const& in="", arg* i=nullptr, bool def=false, bool ismanip=false, arg* m=nullptr) { type=_obj::_variable; varname=in; index=i; definition=def; is_manip=ismanip; precedence=false; manip=m; }
|
||||
~variable() {
|
||||
if(index!=nullptr) delete index;
|
||||
if(manip!=nullptr) delete manip;
|
||||
}
|
||||
|
||||
std::string varname;
|
||||
bool definition;
|
||||
arg* index; // for bash specific
|
||||
|
||||
bool is_manip;
|
||||
bool precedence;
|
||||
arg* manip;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
|
|
@ -260,6 +266,7 @@ class list : public _obj
|
|||
{
|
||||
public:
|
||||
list() { type=_obj::_list; }
|
||||
list(condlist* in) { type=_obj::_list; this->add(in); }
|
||||
~list() { for(auto it: cls) delete it; }
|
||||
|
||||
std::vector<condlist*> cls;
|
||||
|
|
@ -349,6 +356,7 @@ class subshell : public block
|
|||
{
|
||||
public:
|
||||
subshell(list* in=nullptr) { type=_obj::block_subshell; lst=in; }
|
||||
subshell(block* in) { type=_obj::block_subshell; lst=new list(new condlist(in)); }
|
||||
~subshell() {
|
||||
if(lst!=nullptr) delete lst;
|
||||
}
|
||||
|
|
@ -514,22 +522,6 @@ public:
|
|||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class manipulation_subarg : public subarg
|
||||
{
|
||||
public:
|
||||
manipulation_subarg(variable* vr=nullptr, arg* mn=nullptr, bool inq=false) { type=_obj::subarg_manipulation; size=false; var=vr; manip=mn; quoted=inq; }
|
||||
~manipulation_subarg() {
|
||||
if(manip!=nullptr) delete manip;
|
||||
if(var!=nullptr) delete var;
|
||||
}
|
||||
|
||||
bool size;
|
||||
variable* var;
|
||||
arg* manip;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class procsub_subarg : public subarg
|
||||
{
|
||||
public:
|
||||
|
|
@ -606,7 +598,7 @@ public:
|
|||
|
||||
variable* var;
|
||||
|
||||
std::string generate(int ind) { return var->generate(ind); }
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
#endif //STRUC_HPP
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ pipeline* make_pipeline(std::string const& in);
|
|||
condlist* make_condlist(std::string const& in);
|
||||
list* make_list(std::string const& in);
|
||||
|
||||
// copy
|
||||
arg* copy(arg* in);
|
||||
variable* copy(variable* in);
|
||||
|
||||
// testers
|
||||
|
||||
bool arg_has_char(char c, arg* in);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,22 @@
|
|||
#include "debashify.hpp"
|
||||
|
||||
#include "processing.hpp"
|
||||
#include "recursive.hpp"
|
||||
#include "util.hpp"
|
||||
#include "parse.hpp"
|
||||
#include "struc_helper.hpp"
|
||||
|
||||
|
||||
typedef struct debashify_params {
|
||||
bool need_random_string=false;
|
||||
bool need_random_tmpfile=false;
|
||||
bool need_array_create=false;
|
||||
bool need_array_set=false;
|
||||
bool need_array_get=false;
|
||||
std::vector<std::string> debashed_arrays;
|
||||
} debashify_params;
|
||||
|
||||
|
||||
/*
|
||||
[[ ]] debashifying:
|
||||
[[ EXPRESSION && EXPRESSION ]] separated into two parts
|
||||
|
|
@ -40,8 +52,9 @@ block* gen_bashtest_cmd(std::vector<arg*> args)
|
|||
args[1] = new arg(arg1replace);
|
||||
}
|
||||
|
||||
if(args.size() == 3 && args[1]->string() == "=" && arg_has_char('*', args[2]))
|
||||
if(args.size() == 3 && args[1]->string() == "=" && (arg_has_char('*', args[2]) || arg_has_char('?', args[2])) )
|
||||
{
|
||||
// glob matcher: do a case
|
||||
delete args[1];
|
||||
args[1]=nullptr;
|
||||
case_block* tc = new case_block(args[0]);
|
||||
|
|
@ -51,14 +64,16 @@ block* gen_bashtest_cmd(std::vector<arg*> args)
|
|||
}
|
||||
else if(args.size() == 3 && args[1]->string() == "=~")
|
||||
{
|
||||
// regex matcher: use expr
|
||||
delete args[1];
|
||||
args[1]=nullptr;
|
||||
add_quotes(args[2]);
|
||||
ret = make_cmd( std::vector<arg*>({ new arg("expr"), args[0], new arg(":"), args[2] }) );
|
||||
ret->redirs.push_back(new redirect(">", new arg("/dev/null") ));
|
||||
}
|
||||
else // regular [ ]
|
||||
else
|
||||
{
|
||||
// regular [ ]
|
||||
cmd* t = make_cmd(args);
|
||||
t->args->insert(0, new arg("["));
|
||||
t->add(new arg("]"));
|
||||
|
|
@ -121,28 +136,249 @@ bool debashify_bashtest(pipeline* pl)
|
|||
|
||||
bool debashify_declare(cmd* in)
|
||||
{
|
||||
if(in->firstarg_string() == "declare")
|
||||
throw std::runtime_error("Cannot debashify 'declare'");
|
||||
std::string cmd=in->firstarg_string();
|
||||
if(cmd == "declare" || cmd == "typeset" || cmd == "readonly")
|
||||
throw std::runtime_error(strf("Cannot debashify '%s'", cmd.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool debashify_array_def(cmd* in)
|
||||
cmd* make_array_get_cmd(std::string const& varname, arg* index)
|
||||
{
|
||||
for(auto it: in->var_assigns)
|
||||
cmd* c = new cmd(new arglist);
|
||||
// __lxsh_array_get
|
||||
c->args->add( new arg("__lxsh_array_get") );
|
||||
// __lxsh_array_get "$VAR"
|
||||
c->args->add( make_arg("\"$"+varname+"\"") );
|
||||
// __lxsh_array_get "$VAR" N
|
||||
c->args->add( index );
|
||||
return c;
|
||||
}
|
||||
|
||||
subshell_arithmetic* do_debashify_arithmetic(arithmetic* in)
|
||||
{
|
||||
subshell_arithmetic* ret = nullptr;
|
||||
if(in->type == _obj::arithmetic_variable)
|
||||
{
|
||||
if(it.second->size()>0 && it.second->sa[0]->type == _obj::subarg_string && it.second->sa[0]->generate(0) == "(")
|
||||
throw std::runtime_error("Cannot debashify 'VAR=()' arrays");
|
||||
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(in);
|
||||
if(t->var != nullptr && t->var->index != nullptr)
|
||||
{
|
||||
if(t->var->manip != nullptr)
|
||||
throw std::runtime_error("Cannot debashify manipulations on ${VAR[]}");
|
||||
|
||||
std::string varname = t->var->varname;
|
||||
arg* index = t->var->index;
|
||||
t->var->index=nullptr;
|
||||
|
||||
cmd* c = make_array_get_cmd(varname, index);
|
||||
ret = new subshell_arithmetic(new subshell(c));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool debashify_array_call(variable* in)
|
||||
bool debashify_array_arithmetic(_obj* o, debashify_params* params)
|
||||
{
|
||||
if(in->index != nullptr)
|
||||
throw std::runtime_error("Cannot debashify 'VAR[I]' arrays");
|
||||
return false;
|
||||
bool ret=false;
|
||||
switch(o->type)
|
||||
{
|
||||
case _obj::subarg_arithmetic: {
|
||||
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
|
||||
arithmetic* r = do_debashify_arithmetic(t->arith);
|
||||
if(r!=nullptr)
|
||||
{
|
||||
ret=true;
|
||||
delete t->arith;
|
||||
t->arith = r;
|
||||
}
|
||||
} break;
|
||||
case _obj::arithmetic_operation: {
|
||||
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
|
||||
arithmetic* r = do_debashify_arithmetic(t->val1);
|
||||
if(r!=nullptr)
|
||||
{
|
||||
ret=true;
|
||||
delete t->val1;
|
||||
t->val1 = r;
|
||||
}
|
||||
r = do_debashify_arithmetic(t->val2);
|
||||
if(r!=nullptr)
|
||||
{
|
||||
ret=true;
|
||||
delete t->val2;
|
||||
t->val2 = r;
|
||||
}
|
||||
} break;
|
||||
case _obj::arithmetic_parenthesis: {
|
||||
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
|
||||
arithmetic* r = do_debashify_arithmetic(t->val);
|
||||
if(r!=nullptr)
|
||||
{
|
||||
ret=true;
|
||||
delete t->val;
|
||||
t->val = r;
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool debashify_array_get(arg* in, debashify_params* params)
|
||||
{
|
||||
bool has_replaced=false;
|
||||
for(auto it=in->sa.begin() ; it!=in->sa.end() ; it++)
|
||||
{
|
||||
if((*it)->type == _obj::subarg_variable)
|
||||
{
|
||||
variable_subarg* t = dynamic_cast<variable_subarg*>(*it);
|
||||
bool quoted=t->quoted;
|
||||
if(t->var != nullptr && t->var->is_manip && t->var->index != nullptr)
|
||||
{
|
||||
if(t->var->manip != nullptr)
|
||||
throw std::runtime_error("Cannot debashify manipulations on ${VAR[]}");
|
||||
|
||||
params->need_array_get = true;
|
||||
std::string varname = t->var->varname;
|
||||
arg* index = t->var->index;
|
||||
t->var->index=nullptr;
|
||||
|
||||
if(index->string() == "*")
|
||||
{
|
||||
delete index;
|
||||
index = new arg("\\*");
|
||||
}
|
||||
|
||||
cmd* c = make_array_get_cmd(varname, index);
|
||||
subshell_subarg* sb = new subshell_subarg(new subshell(c));
|
||||
sb->quoted=quoted;
|
||||
delete *it;
|
||||
*it = sb;
|
||||
has_replaced=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return has_replaced;
|
||||
}
|
||||
|
||||
bool debashify_array_set(cmd* in, debashify_params* params)
|
||||
{
|
||||
bool has_replaced=false;
|
||||
for(auto it = in->var_assigns.begin() ; it != in->var_assigns.end() ; it++)
|
||||
{
|
||||
if(it->second != nullptr && it->second->size()>0 && it->second->first_sa_string().substr(0,2) == "=(")
|
||||
{
|
||||
// array creation: VAR=()
|
||||
params->need_array_create=true;
|
||||
// extract arguments from =(ARGS...)
|
||||
std::string gen=it->second->generate(0);
|
||||
gen=gen.substr(2);
|
||||
gen.pop_back();
|
||||
// create cmd out of arguments
|
||||
arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).first;
|
||||
cmd* c = new cmd(args);
|
||||
// cmd first argument is __lxsh_array_create
|
||||
c->args->insert(0, new arg("__lxsh_array_create") );
|
||||
subshell_subarg* sb = new subshell_subarg(new subshell(c));
|
||||
// insert new value
|
||||
delete it->second;
|
||||
it->second = new arg("=");
|
||||
it->second->add(sb);
|
||||
has_replaced=true;
|
||||
}
|
||||
else if(it->first != nullptr && it->first->index != nullptr)
|
||||
{
|
||||
// array value set: VAR[]=
|
||||
params->need_array_set=true;
|
||||
force_quotes(it->second);
|
||||
force_quotes(it->first->index);
|
||||
string_subarg* tt=dynamic_cast<string_subarg*>(it->second->sa[0]);
|
||||
|
||||
std::string varname = it->first->varname;
|
||||
arg* index = it->first->index;
|
||||
arg* value = it->second;
|
||||
|
||||
it->first->index = nullptr;
|
||||
it->second = nullptr;
|
||||
|
||||
if(tt->val.substr(0,2) == "+=")
|
||||
{
|
||||
tt->val = tt->val.substr(2); // remove +=
|
||||
// create array get of value
|
||||
cmd* c = make_array_get_cmd(varname, copy(index));
|
||||
subshell_subarg* sb = new subshell_subarg(new subshell(c));
|
||||
sb->quoted=true;
|
||||
value->insert(0, "\"");
|
||||
value->insert(0, sb);
|
||||
value->insert(0, "\"");
|
||||
}
|
||||
else
|
||||
tt->val = tt->val.substr(1); // remove =
|
||||
|
||||
cmd* c = new cmd(new arglist);
|
||||
c->args->add( new arg("__lxsh_array_set") );
|
||||
// __lxsh_array_set "$VAR"
|
||||
c->args->add( make_arg("\"$"+varname+"\"") );
|
||||
// __lxsh_array_set "$VAR" N
|
||||
c->args->add( index );
|
||||
// __lxsh_array_set "$VAR" N value
|
||||
c->args->add( value );
|
||||
// $(__lxsh_array_set "$VAR" N value)
|
||||
subshell_subarg* sb = new subshell_subarg(new subshell(c));
|
||||
|
||||
it->second = new arg("=");
|
||||
it->second->add(sb);
|
||||
has_replaced=true;
|
||||
}
|
||||
else if(it->first != nullptr && it->second->first_sa_string().substr(0,3) == "+=(")
|
||||
{
|
||||
// array add: VAR+=()
|
||||
// can be done by creating a new array with old array + new
|
||||
params->need_array_create=true;
|
||||
|
||||
std::string varname = it->first->varname;
|
||||
|
||||
// extract arguments from =+(ARGS...)
|
||||
std::string gen=it->second->generate(0);
|
||||
gen=gen.substr(3);
|
||||
gen.pop_back();
|
||||
// create cmd out of arguments
|
||||
arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).first;
|
||||
cmd* c = new cmd(args);
|
||||
// cmd first argument is __lxsh_array_create
|
||||
c->args->insert(0, new arg("__lxsh_array_create") );
|
||||
c->args->insert(1, make_arg("\"$"+varname+"\"") );
|
||||
subshell_subarg* sb = new subshell_subarg(new subshell(c));
|
||||
// insert new value
|
||||
delete it->second;
|
||||
it->second = new arg("=");
|
||||
it->second->add(sb);
|
||||
has_replaced=true;
|
||||
|
||||
// throw std::runtime_error("Cannot debashify VAR+=()");
|
||||
}
|
||||
}
|
||||
return has_replaced;
|
||||
}
|
||||
|
||||
bool debashify_plusequal(cmd* in, debashify_params* params)
|
||||
{
|
||||
bool has_replaced=false;
|
||||
for(auto it = in->var_assigns.begin() ; it != in->var_assigns.end() ; it++)
|
||||
{
|
||||
if(it->first != nullptr && it->second->first_sa_string().substr(0,2) == "+=")
|
||||
{
|
||||
string_subarg* tt=dynamic_cast<string_subarg*>(it->second->sa[0]);
|
||||
variable* v = new variable(it->first->varname);
|
||||
v->is_manip=true;
|
||||
tt->val = tt->val.substr(2); // remove +=
|
||||
it->second->insert(0, new variable_subarg(v) );
|
||||
it->second->insert(0, "=");
|
||||
}
|
||||
}
|
||||
return has_replaced;
|
||||
}
|
||||
|
||||
// replace <<< foo by printf %s\n "foo" |
|
||||
bool debashify_herestring(pipeline* pl)
|
||||
{
|
||||
if(pl->cmds.size()>0)
|
||||
|
|
@ -153,7 +389,7 @@ bool debashify_herestring(pipeline* pl)
|
|||
if(c->redirs[i]->op == "<<<")
|
||||
{
|
||||
force_quotes(c->redirs[i]->target);
|
||||
cmd* printcmd = make_cmd("printf '%s\\n'");
|
||||
cmd* printcmd = make_cmd("printf %s\\\\n");
|
||||
printcmd->add(c->redirs[i]->target);
|
||||
pl->cmds.insert(pl->cmds.begin(), printcmd);
|
||||
|
||||
|
|
@ -203,12 +439,12 @@ bool debashify_combined_redirects(block* in)
|
|||
// replace <() and >()
|
||||
/*
|
||||
REPLACE TO:
|
||||
fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)
|
||||
fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random_string 10)
|
||||
mkfifo "$fifoN"
|
||||
( {PSUB;} [>|<] "$fifoN" ; rm "$fifoN") &
|
||||
CMD "$fifoN"
|
||||
*/
|
||||
bool debashify_procsub(list* lst)
|
||||
bool debashify_procsub(list* lst, debashify_params* params)
|
||||
{
|
||||
bool has_replaced=false;
|
||||
for(uint32_t li=0; li<lst->cls.size(); li++)
|
||||
|
|
@ -239,13 +475,14 @@ bool debashify_procsub(list* lst)
|
|||
// perform the replace
|
||||
if(affected_args.size()>0)
|
||||
{
|
||||
params->need_random_tmpfile = true;
|
||||
has_replaced=true;
|
||||
list* lst_insert = new list;
|
||||
std::string mkfifocmd="mkfifo";
|
||||
for(uint32_t i=0; i<affected_args.size(); i++)
|
||||
{
|
||||
// fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)
|
||||
lst_insert->add( make_condlist( strf("__lxshfifo%u=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)", i) ) );
|
||||
// fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random_string 10)
|
||||
lst_insert->add( make_condlist( strf("__lxshfifo%u=$(__lxsh_random_tmpfile lxshfifo)", i) ) );
|
||||
mkfifocmd += strf(" \"$__lxshfifo%u\"", i);
|
||||
}
|
||||
// mkfifo "$fifoN"
|
||||
|
|
@ -257,7 +494,7 @@ bool debashify_procsub(list* lst)
|
|||
procsub_subarg* st = dynamic_cast<procsub_subarg*>(affected_args[i].first->sa[0]);
|
||||
// {PSUB;}
|
||||
brace* cbr = new brace(st->sbsh->lst);
|
||||
// deindex list
|
||||
// deindex list for delete
|
||||
st->sbsh->lst=nullptr;
|
||||
// {PSUB;} > "$__lxshfifoN"
|
||||
cbr->redirs.push_back( new redirect( affected_args[i].second ? "<" : ">", make_arg(strf("\"$__lxshfifo%u\"", i)) ) );
|
||||
|
|
@ -286,26 +523,51 @@ bool debashify_procsub(list* lst)
|
|||
return has_replaced;
|
||||
}
|
||||
|
||||
function* create_random_func()
|
||||
// create the random string generator function
|
||||
//
|
||||
block* create_random_string_func()
|
||||
{
|
||||
std::string code="{ tr -cd '[:alnum:]' </dev/urandom | head -c $1; }";
|
||||
function* fct=parse_function(code.c_str(), code.size(), 0).first;
|
||||
fct->name="__lxsh_random";
|
||||
return fct;
|
||||
std::string code="__lxsh_random_string() { env LC_CTYPE=C tr -dc 'a-zA-Z0-9' </dev/urandom | head -c ${1-20}; }";
|
||||
return parse_block(code.c_str(), code.size(), 0).first;
|
||||
}
|
||||
|
||||
bool r_debashify(_obj* o, bool* need_random_func)
|
||||
block* create_random_tmpfile_func()
|
||||
{
|
||||
std::string code="__lxsh_random_tmpfile() { echo \"${TMPDIR-/tmp}/$1$(__lxsh_random_string 20)\"; }";
|
||||
return parse_block(code.c_str(), code.size(), 0).first;
|
||||
}
|
||||
|
||||
block* create_array_set_func()
|
||||
{
|
||||
std::string code="__lxsh_array_set()\n{\n {\n printf \"%s\\n%s\" \"$3\" \"$1\"\n printf '%*s' \"$(($2+1))\" | tr ' ' \"\\n\"\n } | awk 'BEGIN{RS=\"\\n\"};{if(NR==1){ val=$0 } else if(NR=='\"$(($2+2))\"'){ printf \"%s%s\",val,RS } else { printf \"%s%s\",$0,RS } }'\n}";
|
||||
return parse_block(code.c_str(), code.size(), 0).first;
|
||||
}
|
||||
|
||||
block* create_array_create_func()
|
||||
{
|
||||
std::string code="__lxsh_array_create() {\n for N ; do\n echo \"$N\"\n done\n}";
|
||||
return parse_block(code.c_str(), code.size(), 0).first;
|
||||
}
|
||||
|
||||
block* create_array_get_func()
|
||||
{
|
||||
std::string code="__lxsh_array_get() {\n if [ \"$2\" = \"*\" ] || [ \"$2\" = \"@\" ] ; then\n printf \"%s\" \"$1\" | tr '\\n' ' '\n else\n echo \"$1\" | awk 'BEGIN{RS=\"\\n\"};{if(NR=='\"$(($2+1))\"'){ print } }'\n fi\n}";
|
||||
return parse_block(code.c_str(), code.size(), 0).first;
|
||||
}
|
||||
|
||||
bool r_debashify(_obj* o, debashify_params* params)
|
||||
{
|
||||
// global debashifies
|
||||
debashify_array_arithmetic(o, params);
|
||||
switch(o->type)
|
||||
{
|
||||
case _obj::_variable: {
|
||||
variable* t = dynamic_cast<variable*>(o);
|
||||
debashify_array_call(t);
|
||||
case _obj::_arg: {
|
||||
arg* t = dynamic_cast<arg*>(o);
|
||||
debashify_array_get(t, params);
|
||||
} break;
|
||||
case _obj::_list: {
|
||||
list* t = dynamic_cast<list*>(o);
|
||||
if(debashify_procsub(t))
|
||||
*need_random_func = true;
|
||||
debashify_procsub(t, params);
|
||||
} break;
|
||||
case _obj::_pipeline: {
|
||||
pipeline* t = dynamic_cast<pipeline*>(o);
|
||||
|
|
@ -316,7 +578,8 @@ bool r_debashify(_obj* o, bool* need_random_func)
|
|||
cmd* t = dynamic_cast<cmd*>(o);
|
||||
debashify_combined_redirects(t);
|
||||
debashify_declare(t);
|
||||
debashify_array_def(t);
|
||||
debashify_array_set(t, params);
|
||||
debashify_plusequal(t, params);
|
||||
} break;
|
||||
case _obj::block_subshell: {
|
||||
subshell* t = dynamic_cast<subshell*>(o);
|
||||
|
|
@ -354,12 +617,20 @@ bool r_debashify(_obj* o, bool* need_random_func)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
void debashify(shmain* sh)
|
||||
{
|
||||
bool need_random_func=false;
|
||||
debashify_params params;
|
||||
sh->shebang = "#!/bin/sh";
|
||||
recurse(r_debashify, sh, &need_random_func);
|
||||
if(need_random_func)
|
||||
sh->lst->insert(0, new condlist(create_random_func()));
|
||||
recurse(r_debashify, sh, ¶ms);
|
||||
if(params.need_random_string || params.need_random_tmpfile)
|
||||
sh->lst->insert(0, new condlist(create_random_tmpfile_func()));
|
||||
if(params.need_random_tmpfile)
|
||||
sh->lst->insert(0, new condlist(create_random_string_func()));
|
||||
if(params.need_array_create)
|
||||
sh->lst->insert(0, new condlist(create_array_create_func()));
|
||||
if(params.need_array_set)
|
||||
sh->lst->insert(0, new condlist(create_array_set_func()));
|
||||
if(params.need_array_get)
|
||||
sh->lst->insert(0, new condlist(create_array_get_func()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,14 +362,6 @@ std::string subshell_subarg::generate(int ind)
|
|||
return '$' + sbsh->generate(ind);
|
||||
}
|
||||
|
||||
std::string manipulation_subarg::generate(int ind)
|
||||
{
|
||||
if(size)
|
||||
return "${#" + var->generate(ind) + "}";
|
||||
else
|
||||
return "${" + var->generate(ind) + manip->generate(ind) + "}";
|
||||
}
|
||||
|
||||
std::string procsub_subarg::generate(int ind)
|
||||
{
|
||||
if(is_output)
|
||||
|
|
@ -430,19 +422,30 @@ std::string subshell_arithmetic::generate(int ind)
|
|||
std::string variable_arithmetic::generate(int ind)
|
||||
{
|
||||
std::string ret=var->generate(ind);
|
||||
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS))
|
||||
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip)
|
||||
return '$' + ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string variable::generate(int ind)
|
||||
{
|
||||
if(index!=nullptr)
|
||||
std::string ret;
|
||||
if(is_manip)
|
||||
{
|
||||
return varname + '[' + index->generate(ind) + ']';
|
||||
ret += '{';
|
||||
if(precedence && manip!=nullptr)
|
||||
ret += manip->generate(ind);
|
||||
}
|
||||
else
|
||||
return varname;
|
||||
ret += varname;
|
||||
if(index!=nullptr)
|
||||
ret += '[' + index->generate(ind) + ']';
|
||||
if(is_manip)
|
||||
{
|
||||
if(!precedence && manip!=nullptr)
|
||||
ret += manip->generate(ind);
|
||||
ret += '}';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -211,6 +211,12 @@ std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size,
|
|||
ret = new subshell_arithmetic(ps.first);
|
||||
i=ps.second;
|
||||
}
|
||||
else if(word_eq("${", in, size, i))
|
||||
{
|
||||
auto pm = parse_manipulation(in, size, i+2);
|
||||
ret = new variable_arithmetic(pm.first);
|
||||
i=pm.second;
|
||||
}
|
||||
else if(in[i] == '(')
|
||||
{
|
||||
auto pa = parse_arithmetic(in, size, i+1);
|
||||
|
|
@ -265,26 +271,54 @@ std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size,
|
|||
return std::make_pair(ret, i);
|
||||
}
|
||||
|
||||
std::pair<manipulation_subarg*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start)
|
||||
std::pair<variable*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start)
|
||||
{
|
||||
manipulation_subarg* ret = new manipulation_subarg;
|
||||
variable* ret = nullptr;
|
||||
uint32_t i=start;
|
||||
arg* precede = nullptr;
|
||||
|
||||
if(in[i] == '#')
|
||||
#ifndef NO_PARSE_CATCH
|
||||
try
|
||||
{
|
||||
ret->size=true;
|
||||
#endif
|
||||
;
|
||||
if(in[i] == '#')
|
||||
{
|
||||
precede = new arg("#");
|
||||
i++;
|
||||
}
|
||||
|
||||
auto p=parse_var(in, size, i, true, true);
|
||||
if(p.first == nullptr)
|
||||
throw PARSE_ERROR( "Bad variable name", i );
|
||||
ret = p.first;
|
||||
i = p.second;
|
||||
|
||||
ret->is_manip=true;
|
||||
if(precede != nullptr)
|
||||
{
|
||||
if(in[i] != '}')
|
||||
throw PARSE_ERROR( "Incompatible operations", start );
|
||||
ret->manip = precede;
|
||||
ret->precedence=true;
|
||||
precede=nullptr;
|
||||
}
|
||||
else if(in[i] != '}')
|
||||
{
|
||||
auto pa = parse_arg(in, size, i, "}", NULL, false);
|
||||
ret->manip=pa.first;
|
||||
i = pa.second;
|
||||
}
|
||||
i++;
|
||||
|
||||
#ifndef NO_PARSE_CATCH
|
||||
}
|
||||
|
||||
auto p=parse_var(in, size, i, true, true);
|
||||
if(p.first == nullptr)
|
||||
throw PARSE_ERROR( "Bad variable name", i );
|
||||
ret->var=p.first;
|
||||
i = p.second;
|
||||
|
||||
auto pa = parse_arg(in, size, i, "}", NULL, false);
|
||||
ret->manip=pa.first;
|
||||
i = pa.second+1;
|
||||
catch(ztd::format_error& e)
|
||||
{
|
||||
if(ret != nullptr) delete ret;
|
||||
throw e;
|
||||
}
|
||||
#endif
|
||||
|
||||
return std::make_pair(ret, i);
|
||||
}
|
||||
|
|
@ -343,8 +377,7 @@ void do_one_subarg_step(arg* ret, const char* in, uint32_t size, uint32_t& i, ui
|
|||
ret->add(tmpstr);
|
||||
// get manipulation
|
||||
auto r=parse_manipulation(in, size, i+2);
|
||||
r.first->quoted=is_quoted;
|
||||
ret->add(r.first);
|
||||
ret->add(new variable_subarg(r.first, is_quoted));
|
||||
j = i = r.second;
|
||||
}
|
||||
else if( in[i] == '$' )
|
||||
|
|
|
|||
|
|
@ -450,6 +450,9 @@ std::string gen_json_struc(_obj* o)
|
|||
vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname)));
|
||||
vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition)));
|
||||
vec.push_back(std::make_pair(quote_string("index"), gen_json_struc(t->index)));
|
||||
vec.push_back(std::make_pair(quote_string("is_manip"), boolstring(t->is_manip) ) );
|
||||
vec.push_back(std::make_pair(quote_string("precedence"), boolstring(t->precedence) ) );
|
||||
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
|
||||
break;
|
||||
}
|
||||
case _obj::_redirect :
|
||||
|
|
@ -699,15 +702,6 @@ std::string gen_json_struc(_obj* o)
|
|||
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
||||
break;
|
||||
}
|
||||
case _obj::subarg_manipulation :
|
||||
{
|
||||
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(o);
|
||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_manipulation") ) );
|
||||
vec.push_back(std::make_pair(quote_string("size"), boolstring(t->size) ) );
|
||||
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
|
||||
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
|
||||
break;
|
||||
}
|
||||
case _obj::subarg_procsub :
|
||||
{
|
||||
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o);
|
||||
|
|
|
|||
|
|
@ -61,13 +61,20 @@ list* make_list(std::string const& in)
|
|||
return parse_list_until(in.c_str(), in.size(), 0, 0).first;
|
||||
}
|
||||
|
||||
// copy
|
||||
|
||||
arg* copy(arg* in) {
|
||||
std::string str = in->generate(0);
|
||||
return parse_arg(str.c_str(), str.size(), 0).first;
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
void force_quotes(arg* in)
|
||||
{
|
||||
for(uint32_t i=0; i < in->sa.size() ; i++)
|
||||
{
|
||||
if(!in->sa[i]->quoted && (in->sa[i]->type == _obj::subarg_variable || in->sa[i]->type == _obj::subarg_manipulation || in->sa[i]->type == _obj::subarg_subshell) )
|
||||
if(!in->sa[i]->quoted && (in->sa[i]->type == _obj::subarg_variable || in->sa[i]->type == _obj::subarg_subshell) )
|
||||
{
|
||||
in->sa[i]->quoted=true;
|
||||
in->insert(i+1, new string_subarg("\""));
|
||||
|
|
@ -125,6 +132,13 @@ std::string arg::string()
|
|||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||
}
|
||||
|
||||
std::string arg::first_sa_string()
|
||||
{
|
||||
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string)
|
||||
return "";
|
||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||
}
|
||||
|
||||
std::vector<std::string> arglist::strargs(uint32_t start)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
|
@ -217,16 +231,44 @@ void condlist::prune_first_cmd()
|
|||
|
||||
void arg::insert(uint32_t i, std::string const& in)
|
||||
{
|
||||
this->insert(i, new string_subarg(in));
|
||||
if(i>0 && sa[i-1]->type == _obj::subarg_string)
|
||||
{
|
||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]);
|
||||
t->val += in;
|
||||
}
|
||||
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
||||
{
|
||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]);
|
||||
t->val = in + t->val;
|
||||
}
|
||||
else
|
||||
sa.insert(sa.begin()+i, new string_subarg(in));
|
||||
}
|
||||
void arg::add(std::string const& in)
|
||||
{
|
||||
this->add(new string_subarg(in));
|
||||
this->insert(this->size(), in);
|
||||
}
|
||||
|
||||
void arg::insert(uint32_t i, subarg* val)
|
||||
{
|
||||
sa.insert(sa.begin()+i, val);
|
||||
if(val->type == _obj::subarg_string)
|
||||
{
|
||||
string_subarg* tval = dynamic_cast<string_subarg*>(val);
|
||||
if(i>0 && sa[i-1]->type == _obj::subarg_string)
|
||||
{
|
||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]);
|
||||
t->val += tval->val;
|
||||
}
|
||||
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
||||
{
|
||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]);
|
||||
t->val = tval->val + t->val;
|
||||
}
|
||||
else
|
||||
sa.insert(sa.begin()+i, val);
|
||||
}
|
||||
else
|
||||
sa.insert(sa.begin()+i, val);
|
||||
}
|
||||
void arg::insert(uint32_t i, arg const& a)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue