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:
zawz 2021-02-17 17:00:12 +01:00
parent 65083d09b4
commit fd4c1b0d05
9 changed files with 439 additions and 106 deletions

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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, &params);
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()));
}

View file

@ -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;
}

View file

@ -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] == '$' )

View file

@ -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);

View file

@ -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)
{