improve echo debashifying

This commit is contained in:
zawz 2021-05-28 16:31:17 +02:00
parent 9918bb61ba
commit 8b6a576713
3 changed files with 140 additions and 43 deletions

View file

@ -187,11 +187,15 @@ public:
std::vector<subarg*> sa; std::vector<subarg*> sa;
bool is_string();
// return if is a string and only one subarg // return if is a string and only one subarg
std::string string(); std::string string();
// return if the first subarg is a string // return if the first subarg is a string
std::string first_sa_string(); std::string first_sa_string();
// can expand into multiple arguments
bool can_expand();
inline bool equals(std::string const& in) { return this->string() == in; } inline bool equals(std::string const& in) { return this->string() == in; }
std::string generate(int ind); std::string generate(int ind);
@ -231,6 +235,9 @@ public:
std::vector<std::string> strargs(uint32_t start); std::vector<std::string> strargs(uint32_t start);
// potentially expands into more arguments than its size
bool can_expand();
void insert(uint32_t i, arg* val); void insert(uint32_t i, arg* val);
void insert(uint32_t i, arglist const& lst); void insert(uint32_t i, arglist const& lst);

View file

@ -1,6 +1,6 @@
#include "debashify.hpp" #include "debashify.hpp"
#include "ztd/options.hpp" #include <ztd/options.hpp>
#include "processing.hpp" #include "processing.hpp"
#include "recursive.hpp" #include "recursive.hpp"
@ -144,12 +144,11 @@ std::string get_declare_opt(cmd* in)
ztd::option_set gen_echo_opts() ztd::option_set gen_echo_opts()
{ {
ztd::option_set ret; ztd::option_set ret( std::vector<ztd::option>({
ret.add( ztd::option('e'),
ztd::option('e'), ztd::option('E'),
ztd::option('E'), ztd::option('n')
ztd::option('n') }) );
);
return ret; return ret;
} }
@ -166,6 +165,7 @@ bool debashify_echo(pipeline* pl)
ztd::option_set opts=gen_echo_opts(); ztd::option_set opts=gen_echo_opts();
std::vector<std::string> args=in->args->strargs(1); std::vector<std::string> args=in->args->strargs(1);
std::vector<std::string> postargs; std::vector<std::string> postargs;
try try
{ {
postargs=opts.process(args, {.ignore_numbers=true, .stop_on_argument=true} ); postargs=opts.process(args, {.ignore_numbers=true, .stop_on_argument=true} );
@ -174,52 +174,115 @@ bool debashify_echo(pipeline* pl)
{ {
skip=true; skip=true;
} }
if(skip || postargs.size() == args.size()) // no options processed: skip
return false;
// delete the number of args that were processed bool enable_interpretation=false;
for(uint32_t i=0; i<args.size()-postargs.size(); i++)
{
delete in->args->args[1];
in->args->args.erase(in->args->args.begin()+1);
}
bool doprintf=false;
bool newline=true; bool newline=true;
if(opts['E']) bool has_escape_sequence=false;
bool has_processed_options=false;
if(!skip && postargs.size() != args.size())
{ {
doprintf=true; has_processed_options=true;
} // delete the number of args that were processed
else if(opts['n']) for(uint32_t i=0; i<args.size()-postargs.size(); i++)
{ {
doprintf=true; delete in->args->args[1];
newline=false; in->args->args.erase(in->args->args.begin()+1);
}
if(opts['e'])
enable_interpretation=true;
else if(opts['n'])
newline=false;
} }
if(doprintf) for(auto it=in->args->args.begin()+1; it!=in->args->args.end(); it++)
{ {
delete in->args->args[0]; if(!(*it)->is_string() || (*it)->string().find('\\') != std::string::npos)
in->args->args[0] = new arg("printf");
if(possibly_expands(in->args->args[2]) )
{ {
in->args->insert(1, new arg("%s\\ ")); has_escape_sequence=true;
if(newline) // newline: add a newline command at the end break;
}
}
if(newline && !has_escape_sequence)
{
// newline and no potential escape: don't replace, keep echo
return has_processed_options;
}
else
{
// replace by printf
if(!in->args->can_expand())
{
// no potential expansion: static number of args
std::string format_str = "'";
for(uint32_t i=1; i<in->args->args.size(); i++)
{ {
brace* br = new brace(new list); if(enable_interpretation)
br->lst->add(new condlist(in)); format_str += "%b ";
br->lst->add(make_condlist("echo")); else
pl->cmds[0] = br; format_str += "%s ";
} }
format_str.pop_back();
if(newline)
format_str += "\\n";
format_str += '\'';
in->args->insert(1, new arg(format_str));
delete in->args->args[0];
in->args->args[0] = new arg("printf");
} }
else else
{ {
std::string printfarg="'%s"; std::string format_str;
for(uint32_t i=2; i<in->args->size(); i++) if(enable_interpretation)
printfarg+=" %s"; format_str = "%b";
else
format_str = "%s";
list* lst=nullptr;
// more than 1 arg and first arg can't expand: can split into two printf
// printf '%s' arg1
// printf ' %s' args...
if(in->args->args.size()>2 && !in->args->args[1]->can_expand())
{
// extract arg 1
arg* arg1 = in->args->args[1];
in->args->args.erase(in->args->args.begin()+1);
delete in->args->args[0];
in->args->args[0] = new arg("printf");
lst = new list;
lst->add(new condlist(make_cmd({new arg("printf"), new arg(format_str), arg1 })));
lst->add(new condlist(in));
}
else
{
// can't reliable replace: keep echo if newline
if(newline)
return has_processed_options;
in->args->insert(1, new arg(format_str+"\\ "));
delete in->args->args[0];
in->args->args[0] = new arg("printf");
}
if(newline) if(newline)
printfarg+="\\n"; {
printfarg+="'"; if(lst == nullptr)
in->args->insert(1, new arg(printfarg)); {
lst = new list;
lst->add(new condlist(in));
}
lst->add(make_condlist("echo"));
}
if(lst != nullptr)
{
pl->cmds[0] = new brace(lst);
}
} }
} }

View file

@ -148,20 +148,47 @@ size_t cmd::arglist_size()
// string getters // string getters
bool arg::is_string()
{
return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
}
std::string arg::string() std::string arg::string()
{ {
if(sa.size() != 1 || sa[0]->type != subarg::subarg_string) if(!this->is_string())
return ""; return "";
return dynamic_cast<string_subarg*>(sa[0])->val; return dynamic_cast<string_subarg*>(sa[0])->val;
} }
std::string arg::first_sa_string() std::string arg::first_sa_string()
{ {
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string) if(sa.size() <=0 || sa[0]->type != _obj::subarg_string)
return ""; return "";
return dynamic_cast<string_subarg*>(sa[0])->val; return dynamic_cast<string_subarg*>(sa[0])->val;
} }
bool arg::can_expand()
{
for(auto it: sa)
{
if(it->type != _obj::subarg_string && !it->quoted)
return true;
}
return false;
}
bool arglist::can_expand()
{
bool arg_expands=false;
for(auto it: args)
{
arg_expands = it->can_expand();
if(arg_expands)
return true;
}
return false;
}
std::vector<std::string> arglist::strargs(uint32_t start) std::vector<std::string> arglist::strargs(uint32_t start)
{ {
std::vector<std::string> ret; std::vector<std::string> ret;