diff --git a/include/minimize.hpp b/include/minimize.hpp index 9c64dec..e5b4188 100644 --- a/include/minimize.hpp +++ b/include/minimize.hpp @@ -15,17 +15,25 @@ extern const std::regex regex_null; #define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG" -std::regex var_exclude_regex(std::string const& in); +void require_rescan_all(); +void require_rescan_var(); +void require_rescan_fct(); +void require_rescan_cmd(); + +std::regex var_exclude_regex(std::string const& in, bool include_reserved); std::regex fct_exclude_regex(std::string const& in); void list_vars(_obj* in, std::regex const& exclude); +void list_var_defs(_obj* in, std::regex const& exclude); +void list_var_calls(_obj* in, std::regex const& exclude); void list_fcts(_obj* in, std::regex const& exclude); void list_cmds(_obj* in, std::regex const& exclude); void minimize_var(_obj* in, std::regex const& exclude); void minimize_fct(_obj* in, std::regex const& exclude); -void delete_unused_fct(_obj* in, std::regex const& exclude); -// void delete_unused_var(_obj* in, std::regex const& exclude); +bool delete_unused_fct(_obj* in, std::regex const& exclude); +bool delete_unused_var(_obj* in, std::regex const& exclude); +void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude); #endif //MINIMIZE_HPP diff --git a/include/struc.hpp b/include/struc.hpp index 0acda2c..8168987 100644 --- a/include/struc.hpp +++ b/include/struc.hpp @@ -254,11 +254,14 @@ public: std::string const& firstarg_string(); + size_t arglist_size(); + // preceding var assigns std::vector> var_assigns; // get var assigns in special cmds (export, unset, read) - std::vector arg_vars(); + bool is_argvar(); + std::vector subarg_vars(); arglist* args; diff --git a/src/main.cpp b/src/main.cpp index ce2b52a..ae5c0bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -150,15 +150,19 @@ int main(int argc, char* argv[]) // processing before output if(options['m']) opt_minimize=true; + if(options["remove-unused"]) + delete_unused( sh, re_var_exclude, re_fct_exclude ); if(options["minimize-var"]) minimize_var( sh, re_var_exclude ); if(options["minimize-fct"]) minimize_fct( sh, re_fct_exclude ); - if(options["remove-unused"]) - delete_unused_fct( sh, re_fct_exclude ); if(options["list-var"]) list_vars(sh, re_var_exclude); + else if(options["list-var-def"]) + list_var_defs(sh, re_var_exclude); + else if(options["list-var-call"]) + list_var_calls(sh, re_var_exclude); else if(options["list-fct"]) list_fcts(sh, re_fct_exclude); else if(options["list-cmd"]) diff --git a/src/minimize.cpp b/src/minimize.cpp index bb7d709..109686b 100644 --- a/src/minimize.cpp +++ b/src/minimize.cpp @@ -19,6 +19,64 @@ std::set m_excluded_var, m_excluded_fct, m_excluded_cmd; bool b_gotvar=false, b_gotfct=false, b_gotcmd=false; +// requires + +void require_rescan_var() +{ + b_gotvar = false; + m_vars.clear(); + m_vardefs.clear(); + m_varcalls.clear(); + m_excluded_var.clear(); +} +void require_rescan_fct() +{ + b_gotcmd = false; + m_fcts.clear(); + m_excluded_fct.clear(); +} +void require_rescan_cmd() +{ + b_gotfct = false; + m_cmds.clear(); + m_excluded_cmd.clear(); +} + +void require_rescan_all() +{ + require_rescan_var(); + require_rescan_fct(); + require_rescan_cmd(); +} + +// tools + +countmap_t combine_maps(countmap_t const& a, countmap_t const& b) +{ + countmap_t ret; + for(auto it: a) + { + if(!ret.insert( it ).second) + ret[it.first] += it.second; + } + for(auto it: b) + { + if(!ret.insert( it ).second) + ret[it.first] += it.second; + } + return ret; +} + +void list_map(countmap_t const& map) +{ + uint32_t max=0; + for(auto it: map) + if(it.second > max) + max=it.second; + for(auto it: map) + printf("%*d %s\n", (uint32_t)log10(max)+1, it.second, it.first.c_str()); +} + std::vector get_list(std::string const& in) { return split(in, ", \t\n"); @@ -34,17 +92,21 @@ std::regex gen_regex_from_list(std::vector const& in) return std::regex(re); } -std::vector gen_var_excludes(std::string const& in) +std::vector gen_var_excludes(std::string const& in, bool include_reserved) { - std::vector ret = {RESERVED_VARIABLES, strf("[0-9%s]", SPECIAL_VARS)}; + std::vector ret; + if(include_reserved) + { + ret = {RESERVED_VARIABLES, strf("[0-9%s]", SPECIAL_VARS)}; + } auto t = get_list(in); ret.insert(ret.end(), t.begin(), t.end()); return ret; } -std::regex var_exclude_regex(std::string const& in) +std::regex var_exclude_regex(std::string const& in, bool include_reserved) { - return gen_regex_from_list(gen_var_excludes(in)); + return gen_regex_from_list(gen_var_excludes(in, include_reserved)); } std::regex fct_exclude_regex(std::string const& in) { @@ -65,14 +127,44 @@ bool is_varname(std::string const& in) return true; } -std::vector cmd::arg_vars() +// object extensions // + +std::string get_varname(std::string const& in) +{ + size_t i=in.find('='); + if(i!=std::string::npos) + return in.substr(0, i); + else + return in; +} + +std::string get_varname(arg* in) +{ + if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string) + return ""; + std::string str = in->sa[0]->generate(0); + if(in->sa.size() >= 1 && is_varname(str)) + return get_varname(str); + return ""; +} + +bool cmd_is_argvar(std::string const& in) +{ + return in == "export" || in == "unset" || in == "local" || in == "read"; +} + +bool cmd::is_argvar() +{ + return cmd_is_argvar(this->firstarg_string()); +} + +std::vector cmd::subarg_vars() { std::vector ret; if(args==nullptr || args->size()<=0) return ret; - std::string cmdname=this->firstarg_string(); - if(cmdname == "export" || cmdname == "unset" || cmdname == "local" || cmdname == "read") + if(this->is_argvar()) { for(uint32_t i=1; isize(); i++) { @@ -87,21 +179,11 @@ std::vector cmd::arg_vars() return ret; } -std::string get_varname(subarg* in) -{ - if(in->type != _obj::subarg_string) - return ""; - std::string& t=dynamic_cast(in)->val; - size_t i=t.find('='); - if(i!=std::string::npos) - return t.substr(0, i); - else - return t; -} +/** RECURSIVES **/ -/** VAR RECURSE **/ +// GET // -bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap) +bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap) { switch(in->type) { @@ -125,11 +207,14 @@ bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap) for(auto it: t->var_assigns) if(!defmap->insert( std::make_pair(it.first, 1) ).second) (*defmap)[it.first]++; - for(auto it: t->arg_vars()) + if(t->is_argvar()) { - std::string varname=get_varname(it); - if(!defmap->insert( std::make_pair(varname, 1) ).second) - (*defmap)[varname]++; + for(uint32_t i=1; iargs->size(); i++) + { + std::string varname=get_varname(t->args->args[i]); + if( varname != "" && !defmap->insert( std::make_pair(varname, 1) ).second ) + (*defmap)[varname]++; + } } }; break; default: break; @@ -137,7 +222,38 @@ bool get_var(_obj* in, countmap_t* defmap, countmap_t* callmap) return true; } -bool replace_varname(_obj* in, std::map* varmap) +bool r_get_cmd(_obj* in, countmap_t* all_cmds) +{ + switch(in->type) + { + case _obj::block_cmd: { + cmd* t = dynamic_cast(in); + std::string cmdname = t->firstarg_string(); + if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second) + (*all_cmds)[cmdname]++; + }; break; + default: break; + } + return true; +} + +bool r_get_fct(_obj* in, countmap_t* fct_map) +{ + switch(in->type) + { + case _obj::block_function: { + function* t = dynamic_cast(in); + if(!fct_map->insert( std::make_pair(t->name, 1) ).second) + (*fct_map)[t->name]++; + }; break; + default: break; + } + return true; +} + +// REPLACE // + +bool r_replace_var(_obj* in, std::map* varmap) { switch(in->type) { @@ -167,10 +283,10 @@ bool replace_varname(_obj* in, std::map* varmap) if(el!=varmap->end()) it->first = el->second; } - for(auto it: t->arg_vars()) + for(auto it: t->subarg_vars()) { string_subarg* t = dynamic_cast(it); - auto el=varmap->find(get_varname(t)); + auto el=varmap->find(get_varname(t->val)); if(el!=varmap->end()) { size_t tpos=t->val.find('='); @@ -186,38 +302,7 @@ bool replace_varname(_obj* in, std::map* varmap) return true; } -/** FCT RECURSE **/ - -bool get_cmd(_obj* in, countmap_t* all_cmds) -{ - switch(in->type) - { - case _obj::block_cmd: { - cmd* t = dynamic_cast(in); - std::string cmdname = t->firstarg_string(); - if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second) - (*all_cmds)[cmdname]++; - }; break; - default: break; - } - return true; -} - -bool get_fct(_obj* in, countmap_t* fct_map) -{ - switch(in->type) - { - case _obj::block_function: { - function* t = dynamic_cast(in); - if(!fct_map->insert( std::make_pair(t->name, 1) ).second) - (*fct_map)[t->name]++; - }; break; - default: break; - } - return true; -} - -bool replace_fctname(_obj* in, std::map* fctmap) +bool r_replace_fct(_obj* in, std::map* fctmap) { switch(in->type) { @@ -242,7 +327,9 @@ bool replace_fctname(_obj* in, std::map* fctmap) return true; } -bool delete_fcts(_obj* in, std::set* fcts) +// DELETE // + +bool r_delete_fct(_obj* in, std::set* fcts) { switch(in->type) { @@ -268,7 +355,63 @@ bool delete_fcts(_obj* in, std::set* fcts) return true; } -/** name things **/ +bool r_delete_var(_obj* in, std::set* vars) +{ + switch(in->type) + { + case _obj::_list: { + list* t = dynamic_cast(in); + for(uint32_t i=0; icls.size(); i++) + { + block* tb = t->cls[i]->first_block(); + bool to_delete=false; + if(tb != nullptr && tb->type == _obj::block_cmd) + { + cmd* c = dynamic_cast(tb); + + for(uint32_t j=0; jvar_assigns.size(); j++) + { + if( vars->find(c->var_assigns[j].first) != vars->end() ) + { + delete c->var_assigns[j].second; + c->var_assigns.erase(c->var_assigns.begin()+j); + j--; + } + } + + if(c->is_argvar()) + { + for(uint32_t j=1; jargs->size(); j++) + { + std::string varname=get_varname(c->args->args[j]); + if( varname != "" && vars->find( varname ) != vars->end() ) + { + delete c->args->args[j]; + c->args->args.erase(c->args->args.begin()+j); + j--; + } + } + if(c->args->size()<=1) + to_delete=true; + } + if(c->var_assigns.size()<=0 && c->arglist_size()<=0) + to_delete=true; + + } + if(to_delete) + { + delete t->cls[i]; + t->cls.erase(t->cls.begin()+i); + i--; + } + } + } + default: break; + } + return true; +} + +/** NAME MINIMIZING **/ char nchar(uint32_t n) { @@ -308,53 +451,6 @@ std::string minimal_name(uint32_t n) } } -countmap_t combine_maps(countmap_t const& a, countmap_t const& b) -{ - countmap_t ret; - for(auto it: a) - { - if(!ret.insert( it ).second) - ret[it.first] += it.second; - } - for(auto it: b) - { - if(!ret.insert( it ).second) - ret[it.first] += it.second; - } - return ret; -} - -void varmap_get(_obj* in, std::regex const& exclude) -{ - if(!b_gotvar) - { - b_gotvar=true; - recurse(get_var, in, &m_vardefs, &m_varcalls); - m_vars = combine_maps(m_vardefs, m_varcalls); - m_excluded_var = prune_matching(m_vars, exclude); - } -} - -void fctmap_get(_obj* in, std::regex const& exclude) -{ - if(!b_gotfct) - { - b_gotfct=true; - recurse(get_fct, in, &m_fcts); - m_excluded_fct = prune_matching(m_fcts, exclude); - } -} - -void cmdmap_get(_obj* in, std::regex const& exclude) -{ - if(!b_gotcmd) - { - b_gotcmd=true; - recurse(get_cmd, in, &m_cmds); - m_excluded_fct = prune_matching(m_cmds, exclude); - } -} - std::map gen_minimal_map(countmap_t const& vars, std::set excluded) { std::map ret; @@ -372,6 +468,41 @@ std::map gen_minimal_map(countmap_t const& vars, std::s return ret; } +// map getters + +void varmap_get(_obj* in, std::regex const& exclude) +{ + if(!b_gotvar) + { + b_gotvar=true; + recurse(r_get_var, in, &m_vardefs, &m_varcalls); + m_vars = combine_maps(m_vardefs, m_varcalls); + m_excluded_var = prune_matching(m_vars, exclude); + } +} + +void fctmap_get(_obj* in, std::regex const& exclude) +{ + if(!b_gotfct) + { + b_gotfct=true; + recurse(r_get_fct, in, &m_fcts); + m_excluded_fct = prune_matching(m_fcts, exclude); + } +} + +void cmdmap_get(_obj* in, std::regex const& exclude) +{ + if(!b_gotcmd) + { + b_gotcmd=true; + recurse(r_get_cmd, in, &m_cmds); + m_excluded_fct = prune_matching(m_cmds, exclude); + } +} + +// calls + void minimize_var(_obj* in, std::regex const& exclude) { // countmap_t vars; @@ -382,7 +513,8 @@ void minimize_var(_obj* in, std::regex const& exclude) // create mapping varmap=gen_minimal_map(m_vars, m_excluded_var); // perform replace - recurse(replace_varname, in, &varmap); + recurse(r_replace_var, in, &varmap); + require_rescan_var(); } void minimize_fct(_obj* in, std::regex const& exclude) @@ -399,10 +531,12 @@ void minimize_fct(_obj* in, std::regex const& exclude) // create mapping fctmap=gen_minimal_map(m_fcts, allcmds); // perform replace - recurse(replace_fctname, in, &fctmap); + recurse(r_replace_fct, in, &fctmap); + require_rescan_fct(); + require_rescan_cmd(); } -void delete_unused_fct(_obj* in, std::regex const& exclude) +bool delete_unused_fct(_obj* in, std::regex const& exclude) { std::set unused; // get fcts and cmds @@ -416,10 +550,16 @@ void delete_unused_fct(_obj* in, std::regex const& exclude) } // perform deletion if(unused.size()>0) - recurse(delete_fcts, in, &unused); + { + recurse(r_delete_fct, in, &unused); + require_rescan_all(); + return true; + } + else + return false; } -void delete_unused_var(_obj* in, std::regex const& exclude) +bool delete_unused_var(_obj* in, std::regex const& exclude) { std::set unused; // get fcts and cmds @@ -432,17 +572,18 @@ void delete_unused_var(_obj* in, std::regex const& exclude) } // perform deletion if(unused.size()>0) - recurse(delete_fcts, in, &unused); + { + recurse(r_delete_var, in, &unused); + require_rescan_all(); + return true; + } + else + return false; } -void list_map(countmap_t const& map) +void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude) { - uint32_t max=0; - for(auto it: map) - if(it.second > max) - max=it.second; - for(auto it: map) - printf("%*d %s\n", (uint32_t)log10(max)+1, it.second, it.first.c_str()); + while(delete_unused_fct(in, fct_exclude) || delete_unused_var(in, var_exclude)); } void list_vars(_obj* in, std::regex const& exclude) @@ -451,6 +592,18 @@ void list_vars(_obj* in, std::regex const& exclude) list_map(m_vars); } +void list_var_defs(_obj* in, std::regex const& exclude) +{ + varmap_get(in, exclude); + list_map(m_vardefs); +} + +void list_var_calls(_obj* in, std::regex const& exclude) +{ + varmap_get(in, exclude); + list_map(m_varcalls); +} + void list_fcts(_obj* in, std::regex const& exclude) { fctmap_get(in, exclude); diff --git a/src/options.cpp b/src/options.cpp index c5255fb..889eed5 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -31,10 +31,13 @@ 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 defined and invoked in the script"), + ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"), + ztd::option("list-var", false, "List all variables set and invoked in the script"), + ztd::option("list-var-def", false, "List all variables set in the script"), + ztd::option("list-var-call", false, "List all variables 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("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference"), ztd::option("remove-unused", false, "Remove unused functions") ); return ret; @@ -46,9 +49,9 @@ void get_opts() g_include=!options["no-include"].activated; g_resolve=!options["no-resolve"].activated; if(options["exclude-var"]) - re_var_exclude=var_exclude_regex(options["exclude-var"]); + re_var_exclude=var_exclude_regex(options["exclude-var"], !options["no-exclude-reserved"]); else - re_var_exclude=var_exclude_regex(""); + re_var_exclude=var_exclude_regex("", !options["no-exclude-reserved"]); if(options["exclude-fct"]) re_fct_exclude=fct_exclude_regex(options["exclude-fct"]); } diff --git a/src/resolve.cpp b/src/resolve.cpp index 1473158..49ea432 100644 --- a/src/resolve.cpp +++ b/src/resolve.cpp @@ -319,7 +319,7 @@ std::pair< std::vector , bool > resolve_arg(arg* in, shmain* parent, bool // -- RECURSIVE CALL -- -bool resolve_recurse(_obj* o, shmain* parent) +bool r_resolve(_obj* o, shmain* parent) { switch(o->type) { @@ -409,10 +409,10 @@ bool resolve_recurse(_obj* o, shmain* parent) // recursive call of resolve void resolve(_obj* in, shmain* parent) { - recurse(resolve_recurse, in, parent); + recurse(r_resolve, in, parent); } void resolve(shmain* sh) { - recurse(resolve_recurse, sh, sh); + recurse(r_resolve, sh, sh); } diff --git a/src/struc.cpp b/src/struc.cpp index 44d6ee0..3f7cac3 100644 --- a/src/struc.cpp +++ b/src/struc.cpp @@ -104,6 +104,14 @@ cmd* subshell::single_cmd() return nullptr; } +size_t cmd::arglist_size() +{ + if(args==nullptr) + return 0; + else + return args->size(); +} + cmd* brace::single_cmd() { if( lst->size() == 1 && // only one condlist