Restructure files: separate processing utilities
This commit is contained in:
parent
7e5c505a3f
commit
b4a99d366d
8 changed files with 486 additions and 424 deletions
|
|
@ -6,29 +6,6 @@
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
typedef std::map<std::string,uint32_t> countmap_t;
|
|
||||||
|
|
||||||
extern std::regex re_var_exclude;
|
|
||||||
extern std::regex re_fct_exclude;
|
|
||||||
|
|
||||||
extern const std::regex regex_null;
|
|
||||||
|
|
||||||
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG"
|
|
||||||
|
|
||||||
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_var(_obj* in, std::regex const& exclude);
|
||||||
void minimize_fct(_obj* in, std::regex const& exclude);
|
void minimize_fct(_obj* in, std::regex const& exclude);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,6 @@
|
||||||
|
|
||||||
#define SPECIAL_VARS "!#*@$?"
|
#define SPECIAL_VARS "!#*@$?"
|
||||||
|
|
||||||
inline bool is_num(char c) { return (c >= '0' && c <= '9'); }
|
|
||||||
inline bool is_alpha(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
|
|
||||||
inline bool is_alphanum(char c) { return is_alpha(c) || is_num(c); }
|
|
||||||
|
|
||||||
std::string import_file(std::string const& path);
|
std::string import_file(std::string const& path);
|
||||||
|
|
||||||
shmain* parse_text(const char* in, uint32_t size, std::string const& filename="");
|
shmain* parse_text(const char* in, uint32_t size, std::string const& filename="");
|
||||||
|
|
|
||||||
70
include/processing.hpp
Normal file
70
include/processing.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef PROCESSING_HPP
|
||||||
|
#define PROCESSING_HPP
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "struc.hpp"
|
||||||
|
|
||||||
|
// constants
|
||||||
|
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG"
|
||||||
|
|
||||||
|
// types
|
||||||
|
typedef std::map<std::string,uint32_t> countmap_t;
|
||||||
|
typedef std::map<std::string,std::string> strmap_t;
|
||||||
|
typedef std::set<std::string> set_t;
|
||||||
|
|
||||||
|
// regexes
|
||||||
|
extern std::regex re_var_exclude;
|
||||||
|
extern std::regex re_fct_exclude;
|
||||||
|
extern const std::regex regex_null;
|
||||||
|
|
||||||
|
// Object maps (optimizations)
|
||||||
|
extern countmap_t m_vars, m_vardefs, m_varcalls;
|
||||||
|
extern countmap_t m_fcts, m_cmds;
|
||||||
|
extern set_t m_excluded_var, m_excluded_fct, m_excluded_cmd;
|
||||||
|
|
||||||
|
extern bool b_gotvar, b_gotfct, b_gotcmd;
|
||||||
|
|
||||||
|
/** map get functions (optimizations) **/
|
||||||
|
|
||||||
|
// rescans
|
||||||
|
void require_rescan_all();
|
||||||
|
void require_rescan_var();
|
||||||
|
void require_rescan_fct();
|
||||||
|
void require_rescan_cmd();
|
||||||
|
|
||||||
|
// get objects
|
||||||
|
void varmap_get(_obj* in, std::regex const& exclude);
|
||||||
|
void fctmap_get(_obj* in, std::regex const& exclude);
|
||||||
|
void cmdmap_get(_obj* in, std::regex const& exclude);
|
||||||
|
|
||||||
|
/** functions **/
|
||||||
|
|
||||||
|
// gen regexes
|
||||||
|
std::regex var_exclude_regex(std::string const& in, bool include_reserved);
|
||||||
|
std::regex fct_exclude_regex(std::string const& in);
|
||||||
|
|
||||||
|
// varnames
|
||||||
|
bool is_varname(std::string const& in);
|
||||||
|
std::string get_varname(std::string const& in);
|
||||||
|
std::string get_varname(arg* in);
|
||||||
|
|
||||||
|
// list objects
|
||||||
|
void list_map(countmap_t const& map);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// recursives
|
||||||
|
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap);
|
||||||
|
bool r_get_cmd(_obj* in, countmap_t* all_cmds);
|
||||||
|
bool r_get_fct(_obj* in, countmap_t* fct_map);
|
||||||
|
bool r_delete_fct(_obj* in, set_t* fcts);
|
||||||
|
bool r_delete_var(_obj* in, set_t* vars);
|
||||||
|
|
||||||
|
#endif //PROCESSING_HPP
|
||||||
|
|
@ -28,6 +28,10 @@ std::vector<std::string> split(std::string const& in, char c);
|
||||||
|
|
||||||
std::string escape_str(std::string const& in);
|
std::string escape_str(std::string const& in);
|
||||||
|
|
||||||
|
inline bool is_num(char c) { return (c >= '0' && c <= '9'); }
|
||||||
|
inline bool is_alpha(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
|
||||||
|
inline bool is_alphanum(char c) { return is_alpha(c) || is_num(c); }
|
||||||
|
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
std::string strf( const std::string& format, Args ... args )
|
std::string strf( const std::string& format, Args ... args )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include "recursive.hpp"
|
#include "recursive.hpp"
|
||||||
#include "minimize.hpp"
|
#include "minimize.hpp"
|
||||||
#include "resolve.hpp"
|
#include "resolve.hpp"
|
||||||
|
#include "processing.hpp"
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "g_version.h"
|
#include "g_version.h"
|
||||||
|
|
|
||||||
418
src/minimize.cpp
418
src/minimize.cpp
|
|
@ -1,163 +1,9 @@
|
||||||
#include "minimize.hpp"
|
#include "minimize.hpp"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <regex>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "recursive.hpp"
|
#include "recursive.hpp"
|
||||||
#include "parse.hpp"
|
#include "processing.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
std::regex re_var_exclude;
|
|
||||||
std::regex re_fct_exclude;
|
|
||||||
|
|
||||||
const std::regex regex_null;
|
|
||||||
|
|
||||||
countmap_t m_vars, m_vardefs, m_varcalls;
|
|
||||||
countmap_t m_fcts, m_cmds;
|
|
||||||
std::set<std::string> 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<std::string> get_list(std::string const& in)
|
|
||||||
{
|
|
||||||
return split(in, ", \t\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::regex gen_regex_from_list(std::vector<std::string> const& in)
|
|
||||||
{
|
|
||||||
std::string re;
|
|
||||||
for(auto it: in)
|
|
||||||
re += '('+it+")|";
|
|
||||||
if(re.size()>0)
|
|
||||||
re.pop_back();
|
|
||||||
return std::regex(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> gen_var_excludes(std::string const& in, bool include_reserved)
|
|
||||||
{
|
|
||||||
std::vector<std::string> 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, bool include_reserved)
|
|
||||||
{
|
|
||||||
return gen_regex_from_list(gen_var_excludes(in, include_reserved));
|
|
||||||
}
|
|
||||||
std::regex fct_exclude_regex(std::string const& in)
|
|
||||||
{
|
|
||||||
return gen_regex_from_list(get_list(in));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_varname(std::string const& in)
|
|
||||||
{
|
|
||||||
if(in.size() <= 0 || !(is_alpha(in[0]) || in[0]== '_') )
|
|
||||||
return false;
|
|
||||||
uint32_t i=1;
|
|
||||||
while(i<in.size() && (is_alphanum(in[i]) || in[i] == '_'))
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if(i<in.size() && in[i]!='=')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<subarg*> cmd::subarg_vars()
|
std::vector<subarg*> cmd::subarg_vars()
|
||||||
{
|
{
|
||||||
std::vector<subarg*> ret;
|
std::vector<subarg*> ret;
|
||||||
|
|
@ -181,40 +27,24 @@ std::vector<subarg*> cmd::subarg_vars()
|
||||||
|
|
||||||
/** RECURSIVES **/
|
/** RECURSIVES **/
|
||||||
|
|
||||||
// GET //
|
bool r_replace_fct(_obj* in, strmap_t* fctmap)
|
||||||
|
|
||||||
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
|
|
||||||
{
|
{
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::subarg_variable: {
|
case _obj::block_function: {
|
||||||
variable_subarg* t = dynamic_cast<variable_subarg*>(in);
|
function* t = dynamic_cast<function*>(in);
|
||||||
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
|
auto el=fctmap->find(t->name);
|
||||||
(*callmap)[t->varname]++;
|
if(el!=fctmap->end())
|
||||||
}; break;
|
t->name = el->second;
|
||||||
case _obj::subarg_manipulation: {
|
|
||||||
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(in);
|
|
||||||
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
|
|
||||||
(*callmap)[t->varname]++;
|
|
||||||
}; break;
|
|
||||||
case _obj::block_for: {
|
|
||||||
for_block* t = dynamic_cast<for_block*>(in);
|
|
||||||
if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
|
|
||||||
(*defmap)[t->varname]++;
|
|
||||||
}; break;
|
}; break;
|
||||||
case _obj::block_cmd: {
|
case _obj::block_cmd: {
|
||||||
cmd* t = dynamic_cast<cmd*>(in);
|
cmd* t = dynamic_cast<cmd*>(in);
|
||||||
for(auto it: t->var_assigns)
|
std::string cmdname = t->firstarg_string();
|
||||||
if(!defmap->insert( std::make_pair(it.first, 1) ).second)
|
auto el=fctmap->find(cmdname);
|
||||||
(*defmap)[it.first]++;
|
if(el!=fctmap->end())
|
||||||
if(t->is_argvar())
|
|
||||||
{
|
{
|
||||||
for(uint32_t i=1; i<t->args->size(); i++)
|
delete t->args->args[0];
|
||||||
{
|
t->args->args[0] = new arg(el->second);
|
||||||
std::string varname=get_varname(t->args->args[i]);
|
|
||||||
if( varname != "" && !defmap->insert( std::make_pair(varname, 1) ).second )
|
|
||||||
(*defmap)[varname]++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}; break;
|
}; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
@ -222,38 +52,7 @@ bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool r_get_cmd(_obj* in, countmap_t* all_cmds)
|
bool r_replace_var(_obj* in, strmap_t* varmap)
|
||||||
{
|
|
||||||
switch(in->type)
|
|
||||||
{
|
|
||||||
case _obj::block_cmd: {
|
|
||||||
cmd* t = dynamic_cast<cmd*>(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<function*>(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<std::string,std::string>* varmap)
|
|
||||||
{
|
{
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
|
|
@ -302,115 +101,6 @@ bool r_replace_var(_obj* in, std::map<std::string,std::string>* varmap)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool r_replace_fct(_obj* in, std::map<std::string,std::string>* fctmap)
|
|
||||||
{
|
|
||||||
switch(in->type)
|
|
||||||
{
|
|
||||||
case _obj::block_function: {
|
|
||||||
function* t = dynamic_cast<function*>(in);
|
|
||||||
auto el=fctmap->find(t->name);
|
|
||||||
if(el!=fctmap->end())
|
|
||||||
t->name = el->second;
|
|
||||||
}; break;
|
|
||||||
case _obj::block_cmd: {
|
|
||||||
cmd* t = dynamic_cast<cmd*>(in);
|
|
||||||
std::string cmdname = t->firstarg_string();
|
|
||||||
auto el=fctmap->find(cmdname);
|
|
||||||
if(el!=fctmap->end())
|
|
||||||
{
|
|
||||||
delete t->args->args[0];
|
|
||||||
t->args->args[0] = new arg(el->second);
|
|
||||||
}
|
|
||||||
}; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE //
|
|
||||||
|
|
||||||
bool r_delete_fct(_obj* in, std::set<std::string>* fcts)
|
|
||||||
{
|
|
||||||
switch(in->type)
|
|
||||||
{
|
|
||||||
case _obj::_list: {
|
|
||||||
list* t = dynamic_cast<list*>(in);
|
|
||||||
for(uint32_t i=0; i<t->cls.size(); i++)
|
|
||||||
{
|
|
||||||
block* tb = t->cls[i]->first_block();
|
|
||||||
if(tb != nullptr && tb->type == _obj::block_function)
|
|
||||||
{
|
|
||||||
function* fc = dynamic_cast<function*>(tb);
|
|
||||||
if(fcts->find(fc->name)!=fcts->end())
|
|
||||||
{
|
|
||||||
delete t->cls[i];
|
|
||||||
t->cls.erase(t->cls.begin()+i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool r_delete_var(_obj* in, std::set<std::string>* vars)
|
|
||||||
{
|
|
||||||
switch(in->type)
|
|
||||||
{
|
|
||||||
case _obj::_list: {
|
|
||||||
list* t = dynamic_cast<list*>(in);
|
|
||||||
for(uint32_t i=0; i<t->cls.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<cmd*>(tb);
|
|
||||||
|
|
||||||
for(uint32_t j=0; j<c->var_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; j<c->args->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 **/
|
/** NAME MINIMIZING **/
|
||||||
|
|
||||||
char nchar(uint32_t n)
|
char nchar(uint32_t n)
|
||||||
|
|
@ -451,9 +141,11 @@ std::string minimal_name(uint32_t n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string,std::string> gen_minimal_map(countmap_t const& vars, std::set<std::string> excluded)
|
// vars: input variables
|
||||||
|
// excluded: excluded variables to make sure there is no collision
|
||||||
|
strmap_t gen_minimal_map(countmap_t const& vars, set_t const& excluded)
|
||||||
{
|
{
|
||||||
std::map<std::string,std::string> ret;
|
strmap_t ret;
|
||||||
auto ordered = sort_by_value(vars);
|
auto ordered = sort_by_value(vars);
|
||||||
uint32_t n=0;
|
uint32_t n=0;
|
||||||
for(std::pair<std::string,uint32_t> it: ordered)
|
for(std::pair<std::string,uint32_t> it: ordered)
|
||||||
|
|
@ -468,46 +160,13 @@ std::map<std::string,std::string> gen_minimal_map(countmap_t const& vars, std::s
|
||||||
return ret;
|
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
|
// calls
|
||||||
|
|
||||||
void minimize_var(_obj* in, std::regex const& exclude)
|
void minimize_var(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
// countmap_t vars;
|
// countmap_t vars;
|
||||||
std::set<std::string> excluded;
|
set_t excluded;
|
||||||
std::map<std::string,std::string> varmap;
|
strmap_t varmap;
|
||||||
// get vars
|
// get vars
|
||||||
varmap_get(in, exclude);
|
varmap_get(in, exclude);
|
||||||
// create mapping
|
// create mapping
|
||||||
|
|
@ -520,8 +179,8 @@ void minimize_var(_obj* in, std::regex const& exclude)
|
||||||
void minimize_fct(_obj* in, std::regex const& exclude)
|
void minimize_fct(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
// countmap_t fcts, cmdmap;
|
// countmap_t fcts, cmdmap;
|
||||||
std::set<std::string> allcmds, excluded;
|
set_t allcmds, excluded;
|
||||||
std::map<std::string,std::string> fctmap;
|
strmap_t fctmap;
|
||||||
// get fcts and cmds
|
// get fcts and cmds
|
||||||
fctmap_get(in, exclude);
|
fctmap_get(in, exclude);
|
||||||
cmdmap_get(in, regex_null);
|
cmdmap_get(in, regex_null);
|
||||||
|
|
@ -538,7 +197,7 @@ void minimize_fct(_obj* in, std::regex const& exclude)
|
||||||
|
|
||||||
bool delete_unused_fct(_obj* in, std::regex const& exclude)
|
bool delete_unused_fct(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
std::set<std::string> unused;
|
set_t unused;
|
||||||
// get fcts and cmds
|
// get fcts and cmds
|
||||||
fctmap_get(in, exclude);
|
fctmap_get(in, exclude);
|
||||||
cmdmap_get(in, regex_null);
|
cmdmap_get(in, regex_null);
|
||||||
|
|
@ -561,7 +220,7 @@ bool delete_unused_fct(_obj* in, std::regex const& exclude)
|
||||||
|
|
||||||
bool delete_unused_var(_obj* in, std::regex const& exclude)
|
bool delete_unused_var(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
std::set<std::string> unused;
|
set_t unused;
|
||||||
// get fcts and cmds
|
// get fcts and cmds
|
||||||
varmap_get(in, exclude);
|
varmap_get(in, exclude);
|
||||||
// find unused vars
|
// find unused vars
|
||||||
|
|
@ -584,34 +243,5 @@ 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)
|
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude)
|
||||||
{
|
{
|
||||||
while(delete_unused_fct(in, fct_exclude) || delete_unused_var(in, var_exclude));
|
while(delete_unused_fct(in, fct_exclude) || delete_unused_var(in, var_exclude));
|
||||||
}
|
// keep deleting until both no function and no variables were deleted
|
||||||
|
|
||||||
void list_vars(_obj* in, std::regex const& exclude)
|
|
||||||
{
|
|
||||||
varmap_get(in, 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);
|
|
||||||
list_map(m_fcts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_cmds(_obj* in, std::regex const& exclude)
|
|
||||||
{
|
|
||||||
cmdmap_get(in, exclude);
|
|
||||||
list_map(m_cmds);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "options.hpp"
|
#include "options.hpp"
|
||||||
|
|
||||||
#include "minimize.hpp"
|
#include "processing.hpp"
|
||||||
|
|
||||||
ztd::option_set options = gen_options();
|
ztd::option_set options = gen_options();
|
||||||
bool opt_minimize=false;
|
bool opt_minimize=false;
|
||||||
|
|
@ -37,8 +37,8 @@ ztd::option_set gen_options()
|
||||||
ztd::option("list-var-call", false, "List all variables invoked 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-fct", false, "List all functions defined in the script"),
|
||||||
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
||||||
// 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 and variables")
|
||||||
ztd::option("remove-unused", false, "Remove unused functions")
|
// ztd::option("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference")
|
||||||
);
|
);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
384
src/processing.cpp
Normal file
384
src/processing.cpp
Normal file
|
|
@ -0,0 +1,384 @@
|
||||||
|
#include "processing.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "recursive.hpp"
|
||||||
|
#include "parse.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
// Global regex
|
||||||
|
|
||||||
|
std::regex re_var_exclude;
|
||||||
|
std::regex re_fct_exclude;
|
||||||
|
|
||||||
|
const std::regex regex_null;
|
||||||
|
|
||||||
|
// Object maps
|
||||||
|
|
||||||
|
countmap_t m_vars, m_vardefs, m_varcalls;
|
||||||
|
countmap_t m_fcts, m_cmds;
|
||||||
|
set_t 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 **/
|
||||||
|
|
||||||
|
// type 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<std::string> get_list(std::string const& in)
|
||||||
|
{
|
||||||
|
return split(in, ", \t\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::regex gen_regex_from_list(std::vector<std::string> const& in)
|
||||||
|
{
|
||||||
|
std::string re;
|
||||||
|
for(auto it: in)
|
||||||
|
re += '('+it+")|";
|
||||||
|
if(re.size()>0)
|
||||||
|
re.pop_back();
|
||||||
|
return std::regex(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> gen_var_excludes(std::string const& in, bool include_reserved)
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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, bool include_reserved)
|
||||||
|
{
|
||||||
|
return gen_regex_from_list(gen_var_excludes(in, include_reserved));
|
||||||
|
}
|
||||||
|
std::regex fct_exclude_regex(std::string const& in)
|
||||||
|
{
|
||||||
|
return gen_regex_from_list(get_list(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable checks and extensions
|
||||||
|
|
||||||
|
bool is_varname(std::string const& in)
|
||||||
|
{
|
||||||
|
if(in.size() <= 0 || !(is_alpha(in[0]) || in[0]== '_') )
|
||||||
|
return false;
|
||||||
|
uint32_t i=1;
|
||||||
|
while(i<in.size() && (is_alphanum(in[i]) || in[i] == '_'))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i<in.size() && in[i]!='=')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OUTPUT **/
|
||||||
|
|
||||||
|
|
||||||
|
void list_vars(_obj* in, std::regex const& exclude)
|
||||||
|
{
|
||||||
|
varmap_get(in, 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);
|
||||||
|
list_map(m_fcts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_cmds(_obj* in, std::regex const& exclude)
|
||||||
|
{
|
||||||
|
cmdmap_get(in, exclude);
|
||||||
|
list_map(m_cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** RECURSIVES **/
|
||||||
|
|
||||||
|
// GET //
|
||||||
|
|
||||||
|
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
|
||||||
|
{
|
||||||
|
switch(in->type)
|
||||||
|
{
|
||||||
|
case _obj::subarg_variable: {
|
||||||
|
variable_subarg* t = dynamic_cast<variable_subarg*>(in);
|
||||||
|
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
|
||||||
|
(*callmap)[t->varname]++;
|
||||||
|
}; break;
|
||||||
|
case _obj::subarg_manipulation: {
|
||||||
|
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(in);
|
||||||
|
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
|
||||||
|
(*callmap)[t->varname]++;
|
||||||
|
}; break;
|
||||||
|
case _obj::block_for: {
|
||||||
|
for_block* t = dynamic_cast<for_block*>(in);
|
||||||
|
if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
|
||||||
|
(*defmap)[t->varname]++;
|
||||||
|
}; break;
|
||||||
|
case _obj::block_cmd: {
|
||||||
|
cmd* t = dynamic_cast<cmd*>(in);
|
||||||
|
for(auto it: t->var_assigns)
|
||||||
|
if(!defmap->insert( std::make_pair(it.first, 1) ).second)
|
||||||
|
(*defmap)[it.first]++;
|
||||||
|
if(t->is_argvar())
|
||||||
|
{
|
||||||
|
for(uint32_t i=1; i<t->args->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;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r_get_cmd(_obj* in, countmap_t* all_cmds)
|
||||||
|
{
|
||||||
|
switch(in->type)
|
||||||
|
{
|
||||||
|
case _obj::block_cmd: {
|
||||||
|
cmd* t = dynamic_cast<cmd*>(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<function*>(in);
|
||||||
|
if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
|
||||||
|
(*fct_map)[t->name]++;
|
||||||
|
}; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE //
|
||||||
|
|
||||||
|
bool r_delete_fct(_obj* in, set_t* fcts)
|
||||||
|
{
|
||||||
|
switch(in->type)
|
||||||
|
{
|
||||||
|
case _obj::_list: {
|
||||||
|
list* t = dynamic_cast<list*>(in);
|
||||||
|
for(uint32_t i=0; i<t->cls.size(); i++)
|
||||||
|
{
|
||||||
|
block* tb = t->cls[i]->first_block();
|
||||||
|
if(tb != nullptr && tb->type == _obj::block_function)
|
||||||
|
{
|
||||||
|
function* fc = dynamic_cast<function*>(tb);
|
||||||
|
if(fcts->find(fc->name)!=fcts->end())
|
||||||
|
{
|
||||||
|
delete t->cls[i];
|
||||||
|
t->cls.erase(t->cls.begin()+i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r_delete_var(_obj* in, set_t* vars)
|
||||||
|
{
|
||||||
|
switch(in->type)
|
||||||
|
{
|
||||||
|
case _obj::_list: {
|
||||||
|
list* t = dynamic_cast<list*>(in);
|
||||||
|
for(uint32_t i=0; i<t->cls.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<cmd*>(tb);
|
||||||
|
|
||||||
|
for(uint32_t j=0; j<c->var_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; j<c->args->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;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue