From fd4c1b0d0543e7cbdeea478ced5cfa5dcc355d90 Mon Sep 17 00:00:00 2001 From: zawz Date: Wed, 17 Feb 2021 17:00:12 +0100 Subject: [PATCH] major changes: structure: remove manipulation class integrate into variable class debashify: implement debashify on indexed arrays parsing: can now parse manipulations in arithmetics --- include/parse.hpp | 2 +- include/recursive.hpp | 8 +- include/struc.hpp | 32 ++-- include/struc_helper.hpp | 4 + src/debashify.cpp | 343 +++++++++++++++++++++++++++++++++++---- src/generate.cpp | 29 ++-- src/parse.cpp | 65 ++++++-- src/processing.cpp | 12 +- src/struc_helper.cpp | 50 +++++- 9 files changed, 439 insertions(+), 106 deletions(-) diff --git a/include/parse.hpp b/include/parse.hpp index 6d02da6..edfcbc9 100644 --- a/include/parse.hpp +++ b/include/parse.hpp @@ -47,7 +47,7 @@ std::pair parse_var(const char* in, uint32_t size, uint32_t // subarg parsers std::pair parse_arithmetic(const char* in, uint32_t size, uint32_t start); -std::pair parse_manipulation(const char* in, uint32_t size, uint32_t start); +std::pair parse_manipulation(const char* in, uint32_t size, uint32_t start); // arg parser std::pair 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 diff --git a/include/recursive.hpp b/include/recursive.hpp index 776d2e1..d06d7b5 100644 --- a/include/recursive.hpp +++ b/include/recursive.hpp @@ -23,6 +23,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args) { variable* t = dynamic_cast(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(o); - recurse(fct, t->var, args...); - recurse(fct, t->manip, args...); - break; - } case _obj::subarg_procsub : { procsub_subarg* t = dynamic_cast(o); diff --git a/include/struc.hpp b/include/struc.hpp index da1b95a..da77f67 100644 --- a/include/struc.hpp +++ b/include/struc.hpp @@ -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 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 diff --git a/include/struc_helper.hpp b/include/struc_helper.hpp index 591d551..6ce5870 100644 --- a/include/struc_helper.hpp +++ b/include/struc_helper.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); diff --git a/src/debashify.cpp b/src/debashify.cpp index b6ad60a..790e7f0 100644 --- a/src/debashify.cpp +++ b/src/debashify.cpp @@ -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 debashed_arrays; +} debashify_params; + + /* [[ ]] debashifying: [[ EXPRESSION && EXPRESSION ]] separated into two parts @@ -40,8 +52,9 @@ block* gen_bashtest_cmd(std::vector 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 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({ 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(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(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(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(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(*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(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(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; licls.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; iadd( 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(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:]' name="__lxsh_random"; - return fct; + std::string code="__lxsh_random_string() { env LC_CTYPE=C tr -dc 'a-zA-Z0-9' type) { - case _obj::_variable: { - variable* t = dynamic_cast(o); - debashify_array_call(t); + case _obj::_arg: { + arg* t = dynamic_cast(o); + debashify_array_get(t, params); } break; case _obj::_list: { list* t = dynamic_cast(o); - if(debashify_procsub(t)) - *need_random_func = true; + debashify_procsub(t, params); } break; case _obj::_pipeline: { pipeline* t = dynamic_cast(o); @@ -316,7 +578,8 @@ bool r_debashify(_obj* o, bool* need_random_func) cmd* t = dynamic_cast(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(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())); } diff --git a/src/generate.cpp b/src/generate.cpp index a4052ef..173d4d1 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -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; } diff --git a/src/parse.cpp b/src/parse.cpp index f54e992..9ad8f41 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -211,6 +211,12 @@ std::pair 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 parse_arithmetic(const char* in, uint32_t size, return std::make_pair(ret, i); } -std::pair parse_manipulation(const char* in, uint32_t size, uint32_t start) +std::pair 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] == '$' ) diff --git a/src/processing.cpp b/src/processing.cpp index e02a7bd..e1267a1 100644 --- a/src/processing.cpp +++ b/src/processing.cpp @@ -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(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(o); diff --git a/src/struc_helper.cpp b/src/struc_helper.cpp index 676084f..6b96374 100644 --- a/src/struc_helper.cpp +++ b/src/struc_helper.cpp @@ -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(sa[0])->val; } +std::string arg::first_sa_string() +{ + if(sa.size() <=0 || sa[0]->type != subarg::subarg_string) + return ""; + return dynamic_cast(sa[0])->val; +} + std::vector arglist::strargs(uint32_t start) { std::vector 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(sa[i-1]); + t->val += in; + } + else if(itype == _obj::subarg_string) + { + string_subarg* t = dynamic_cast(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(val); + if(i>0 && sa[i-1]->type == _obj::subarg_string) + { + string_subarg* t = dynamic_cast(sa[i-1]); + t->val += tval->val; + } + else if(itype == _obj::subarg_string) + { + string_subarg* t = dynamic_cast(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) {