diff --git a/include/struc.hpp b/include/struc.hpp index b6bacc3..cacb0f1 100644 --- a/include/struc.hpp +++ b/include/struc.hpp @@ -82,7 +82,7 @@ class _obj { public: enum _objtype { - subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, + subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_manipulation, _arg, _arglist, _pipeline, @@ -439,5 +439,18 @@ public: std::string generate(int ind); }; +class manipulation_subarg : public subarg +{ +public: + manipulation_subarg(arg* in=nullptr) { type=_obj::subarg_manipulation; size=false; manip=in; } + ~manipulation_subarg() { if(manip!=nullptr) delete manip; } + + bool size; + std::string varname; + arg* manip; + + std::string generate(int ind); +}; + #endif //STRUC_HPP diff --git a/src/generate.cpp b/src/generate.cpp index 4c35616..6670bbf 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -330,10 +330,15 @@ std::string cmd::generate(int ind) std::string subshell_subarg::generate(int ind) { - std::string ret; - ret += '$'; - ret += sbsh->generate(ind); - return ret; + return '$' + sbsh->generate(ind); +} + +std::string manipulation_subarg::generate(int ind) +{ + if(size) + return "${#" + varname + "}"; + else + return "${" + varname + manip->generate(ind) + "}"; } // TEMPLATE diff --git a/src/minimize.cpp b/src/minimize.cpp index 800e079..83ee296 100644 --- a/src/minimize.cpp +++ b/src/minimize.cpp @@ -98,6 +98,11 @@ void get_map_varname(_obj* in, std::map* variable_map) if(!variable_map->insert( std::make_pair(t->varname, 1) ).second) (*variable_map)[t->varname]++; }; break; + case _obj::subarg_manipulation: { + manipulation_subarg* t = dynamic_cast(in); + if(!variable_map->insert( std::make_pair(t->varname, 1) ).second) + (*variable_map)[t->varname]++; + }; break; case _obj::block_for: { for_block* t = dynamic_cast(in); if(!variable_map->insert( std::make_pair(t->varname, 1) ).second) @@ -129,6 +134,12 @@ void replace_varname(_obj* in, std::map* varmap) if(el!=varmap->end()) t->varname = el->second; }; break; + case _obj::subarg_manipulation: { + manipulation_subarg* t = dynamic_cast(in); + auto el=varmap->find(t->varname); + if(el!=varmap->end()) + t->varname = el->second; + }; break; case _obj::block_for: { for_block* t = dynamic_cast(in); auto it=varmap->find(t->varname); diff --git a/src/options.cpp b/src/options.cpp index 107dd4c..a7fe217 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -30,9 +30,9 @@ ztd::option_set gen_options() ztd::option("minimize-fct", false, "Minimize function names"), ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"), ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"), - ztd::option("list-var", false, "List all variables invoked in the script"), - ztd::option("list-fct", false, "List all functions invoked in the script"), - ztd::option("list-cmd", false, "List all functions invoked in the script"), + ztd::option("list-var", false, "List all variables defined and invoked in the script"), + ztd::option("list-fct", false, "List all functions defined in the script"), + ztd::option("list-cmd", false, "List all commands invoked in the script"), // ztd::option("unset-var", false, "Add 'unset' to vars"), ztd::option("remove-unused", false, "Remove unused functions") ); diff --git a/src/parse.cpp b/src/parse.cpp index ceb78a0..a200679 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -176,10 +176,36 @@ std::pair parse_arithmetic(const char* in, uint32_ return std::make_pair(ret, i); } +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); + +std::pair parse_manipulation(const char* in, uint32_t size, uint32_t start) +{ + manipulation_subarg* ret = new manipulation_subarg; + uint32_t i=start; + + if(in[i] == '#') + { + ret->size=true; + i++; + } + + auto p=parse_varname(in, size, i); + if(p.second == i) + throw PARSE_ERROR( "Bad variable name", i ); + ret->varname=p.first; + i = p.second; + + auto pa = parse_arg(in, size, i, "}", NULL, false); + ret->manip=pa.first; + i = pa.second+1; + + return std::make_pair(ret, i); +} + // parse one argument // must start at a read char // ends at either " \t|&;\n()" -std::pair parse_arg(const char* in, uint32_t size, uint32_t start) +std::pair parse_arg(const char* in, uint32_t size, uint32_t start, const char* end, const char* unexpected, bool doquote) { arg* ret = new arg; // j : start of subarg , q = start of quote @@ -188,23 +214,23 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star try { - if(is_in(in[i], SPECIAL_TOKENS)) + if(unexpected != NULL && is_in(in[i], unexpected)) throw PARSE_ERROR( strf("Unexpected token '%c'", in[i]) , i); - while(i") && in[i+1]=='&') // special case for <& and >& { i+=2; } - else if(in[i]=='\\') // backslash: don't check next char + else if(doquote && in[i]=='\\') // backslash: don't check next char { i++; if(i>=size) - break; + break; i++; } - else if(in[i] == '"') // start double quote + else if(doquote && in[i] == '"') // start double quote { q=i; i++; @@ -218,9 +244,8 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star { // add previous subarg ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); - i+=3; // get arithmetic - auto r=parse_arithmetic(in, size, i); + auto r=parse_arithmetic(in, size, i+3); ret->sa.push_back(r.first); j = i = r.second; } @@ -228,12 +253,20 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star { // add previous subarg ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); - i+=2; // get subshell - auto r=parse_subshell(in, size, i); + auto r=parse_subshell(in, size, i+2); ret->sa.push_back(new subshell_subarg(r.first, true)); j = i = r.second; } + else if( word_eq("${", in, size, i) ) // variable manipulation + { + // add previous subarg + ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); + // get manipulation + auto r=parse_manipulation(in, size, i+2); + ret->sa.push_back(r.first); + j = i = r.second; + } else if( in[i] == '$' ) { auto r=parse_varname(in, size, i+1); @@ -256,7 +289,7 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star } i++; } - else if(in[i] == '\'') // start single quote + else if(doquote && in[i] == '\'') // start single quote { q=i; i++; @@ -270,9 +303,8 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star { // add previous subarg ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); - i+=3; // get arithmetic - auto r=parse_arithmetic(in, size, i); + auto r=parse_arithmetic(in, size, i+3); ret->sa.push_back(r.first); j = i = r.second; } @@ -280,12 +312,20 @@ std::pair parse_arg(const char* in, uint32_t size, uint32_t star { // add previous subarg ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); - i+=2; // get subshell - auto r=parse_subshell(in, size, i); + auto r=parse_subshell(in, size, i+2); ret->sa.push_back(new subshell_subarg(r.first, false)); j = i = r.second; } + else if( word_eq("${", in, size, i) ) // variable manipulation + { + // add previous subarg + ret->sa.push_back(new string_subarg(std::string(in+j, i-j))); + // get manipulation + auto r=parse_manipulation(in, size, i+2); + ret->sa.push_back(r.first); + j = i = r.second; + } else if( in[i] == '$' ) { auto r=parse_varname(in, size, i+1);