From 8b701328bcd0854f942747deebb7a5b1bdefc970 Mon Sep 17 00:00:00 2001 From: zawwz Date: Thu, 11 Mar 2021 14:54:15 +0100 Subject: [PATCH] implement quote minimizing --- include/minimize.hpp | 2 + include/version.h | 2 +- src/generate.cpp | 2 +- src/main.cpp | 3 + src/minimize.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 2 deletions(-) diff --git a/include/minimize.hpp b/include/minimize.hpp index 114da7e..eb6f61e 100644 --- a/include/minimize.hpp +++ b/include/minimize.hpp @@ -13,4 +13,6 @@ 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); +void minimize_quotes(_obj* in); + #endif //MINIMIZE_HPP diff --git a/include/version.h b/include/version.h index 4038084..eb50c34 100644 --- a/include/version.h +++ b/include/version.h @@ -1,6 +1,6 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION_STRING "v1.0.0" +#define VERSION_STRING "v1.1.0" #endif //VERSION_H diff --git a/src/generate.cpp b/src/generate.cpp index 173d4d1..8db7478 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -342,7 +342,7 @@ std::string cmd::generate(int ind) // command ret += args->generate(ind); // delete potential trailing space - if(ret[ret.size()-1] == ' ') + if(ret.size()>2 && ret[ret.size()-1] == ' ' && ret[ret.size()-2] != '\\') ret.pop_back(); } else // empty command: remove trailing space diff --git a/src/main.cpp b/src/main.cpp index b1e5376..5b0e7fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -167,7 +167,10 @@ int main(int argc, char* argv[]) // processing before output // minimize if(options['m']) + { + minimize_quotes(sh); opt_minimize=true; + } if(options["remove-unused"]) delete_unused( sh, re_var_exclude, re_fct_exclude ); if(options["minimize-var"]) diff --git a/src/minimize.cpp b/src/minimize.cpp index 189313a..ca8ae5b 100644 --- a/src/minimize.cpp +++ b/src/minimize.cpp @@ -1,5 +1,7 @@ #include "minimize.hpp" + +#include "parse.hpp" #include "recursive.hpp" #include "processing.hpp" #include "util.hpp" @@ -67,6 +69,158 @@ bool r_replace_var(_obj* in, strmap_t* varmap) return true; } +const char* escaped_char=" \\\t!\"()|&*?"; +const char* doublequote_escape_char=" \t'|&\\*?"; +uint32_t count_escape_chars(std::string const& in, bool doublequote) +{ + uint32_t r=0; + for(uint32_t i=0; i=in.size()) + continue; + else if(is_in(in[i+1], SPECIAL_VARS) || is_alphanum(in[i+1]) || in[i+1] == '_' || in[i+1] == '(') + { + if(doublequote) // doublequote: can't remove otherwise not quoted var + return 2; + r++; + } + } + } + return r; +} + +bool is_this_quote(char c, bool is_doublequote) +{ + if(is_doublequote) + return c == '"'; + else + return c == '\''; +} + +void do_one_minimize_quotes(string_subarg* in, bool prev_is_var, bool start_quoted) +{ + std::string& val = in->val; + if(val.size() <= 1) + return; + if(start_quoted) // don't handle start quoted for now + return; + if(val[0] == '"' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip + return; + if(val[0] == '\'' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip + return; + + uint32_t i=0, j=0; + while( i < val.size() ) + { + bool doublequote=false; + while(i=val.size()) // end before finding quote: exit + return; + if(val[i] == '"') + doublequote=true; + + j=i; + i++; + + if(doublequote) + { + while(i=val.size()) // end before finding quote: exit + return; + } + else + { + while(i=val.size()) // end before finding quote: exit + return; + + } + uint32_t ce = count_escape_chars(val.substr(j+1, i-j-1), doublequote); + if(ce == 0) + { + val.erase(val.begin()+i); + val.erase(val.begin()+j); + } + else if(ce == 1) // only one char to escape: can save some space + { + val.erase(val.begin()+i); + val.erase(val.begin()+j); + uint32_t k; + if(doublequote) + { + for(k=j; ktype) + { + case _obj::_arg: { + arg* t = dynamic_cast(in); + for(uint32_t i=0; isa.size(); i++) + { + if(t->sa[i]->type == _obj::subarg_string) + { + string_subarg* ss = dynamic_cast(t->sa[i]); + bool prev_is_var=false; + if(i>0 && t->sa[i-1]->type == _obj::subarg_variable) + { + variable_subarg* vs = dynamic_cast(t->sa[i-1]); + if(vs->var != nullptr && vs->var->is_manip == false && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_alpha(vs->var->varname[0]) ) ) + prev_is_var=true; + } + if(t->sa.size()==1 && (ss->val=="\"\"" || ss->val=="''") ) // single argument as "" or '': don't minimize + continue; + do_one_minimize_quotes(ss, prev_is_var, i>0 && t->sa[i-1]->quoted); + } + //if() + } + }; break; + default: break; + } + return true; +} + /** NAME MINIMIZING **/ char nchar(uint32_t n) @@ -208,6 +362,11 @@ bool delete_unused_var(_obj* in, std::regex const& exclude) return false; } +void minimize_quotes(_obj* in) +{ + recurse(r_minimize_useless_quotes, in); +} + 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));