implement quote minimizing

This commit is contained in:
zawwz 2021-03-11 14:54:15 +01:00
parent f0ed4e2602
commit 8b701328bc
5 changed files with 166 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"])

View file

@ -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(); i++)
{
if(doublequote && is_in(in[i], doublequote_escape_char))
r++;
else if(!doublequote && is_in(in[i], escaped_char))
r++;
else if(in[i] == '\n') // \n: can't remove quotes
return 2;
else if(in[i] == '$')
{
if(i+1>=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() && !( val[i] == '\'' || val[i] == '"') )
{
if(val[i] == '\\')
i++;
i++;
}
if(i>=val.size()) // end before finding quote: exit
return;
if(val[i] == '"')
doublequote=true;
j=i;
i++;
if(doublequote)
{
while(i<val.size() && val[i] != '"')
{
if(val[i] == '\\')
i++;
i++;
}
if(i>=val.size()) // end before finding quote: exit
return;
}
else
{
while(i<val.size() && val[i] != '\'')
i++;
if(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; k<i-1; k++)
{
if( is_in(val[k], doublequote_escape_char) )
break;
}
}
else
{
for(k=j; k<i-1; k++)
{
if( is_in(val[k], escaped_char) )
break;
if( k+1<val.size() && val[k] == '$' && ( is_in(val[k+1], SPECIAL_VARS) || is_alpha(val[k+1]) || val[k+1] == '_' ) )
break;
}
}
if(k<i-1)
val.insert(val.begin()+k, '\\');
}
}
}
bool r_minimize_useless_quotes(_obj* in)
{
switch(in->type)
{
case _obj::_arg: {
arg* t = dynamic_cast<arg*>(in);
for(uint32_t i=0; i<t->sa.size(); i++)
{
if(t->sa[i]->type == _obj::subarg_string)
{
string_subarg* ss = dynamic_cast<string_subarg*>(t->sa[i]);
bool prev_is_var=false;
if(i>0 && t->sa[i-1]->type == _obj::subarg_variable)
{
variable_subarg* vs = dynamic_cast<variable_subarg*>(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));