improve echo debashifying
This commit is contained in:
parent
9918bb61ba
commit
8b6a576713
3 changed files with 140 additions and 43 deletions
|
|
@ -187,11 +187,15 @@ public:
|
|||
|
||||
std::vector<subarg*> sa;
|
||||
|
||||
bool is_string();
|
||||
// return if is a string and only one subarg
|
||||
std::string string();
|
||||
// return if the first subarg is a 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; }
|
||||
|
||||
std::string generate(int ind);
|
||||
|
|
@ -231,6 +235,9 @@ public:
|
|||
|
||||
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, arglist const& lst);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "debashify.hpp"
|
||||
|
||||
#include "ztd/options.hpp"
|
||||
#include <ztd/options.hpp>
|
||||
|
||||
#include "processing.hpp"
|
||||
#include "recursive.hpp"
|
||||
|
|
@ -144,12 +144,11 @@ std::string get_declare_opt(cmd* in)
|
|||
|
||||
ztd::option_set gen_echo_opts()
|
||||
{
|
||||
ztd::option_set ret;
|
||||
ret.add(
|
||||
ztd::option('e'),
|
||||
ztd::option('E'),
|
||||
ztd::option('n')
|
||||
);
|
||||
ztd::option_set ret( std::vector<ztd::option>({
|
||||
ztd::option('e'),
|
||||
ztd::option('E'),
|
||||
ztd::option('n')
|
||||
}) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +165,7 @@ bool debashify_echo(pipeline* pl)
|
|||
ztd::option_set opts=gen_echo_opts();
|
||||
std::vector<std::string> args=in->args->strargs(1);
|
||||
std::vector<std::string> postargs;
|
||||
|
||||
try
|
||||
{
|
||||
postargs=opts.process(args, {.ignore_numbers=true, .stop_on_argument=true} );
|
||||
|
|
@ -174,52 +174,115 @@ bool debashify_echo(pipeline* pl)
|
|||
{
|
||||
skip=true;
|
||||
}
|
||||
if(skip || postargs.size() == args.size()) // no options processed: skip
|
||||
return false;
|
||||
|
||||
// delete the number of args that were processed
|
||||
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 enable_interpretation=false;
|
||||
bool newline=true;
|
||||
if(opts['E'])
|
||||
bool has_escape_sequence=false;
|
||||
bool has_processed_options=false;
|
||||
|
||||
if(!skip && postargs.size() != args.size())
|
||||
{
|
||||
doprintf=true;
|
||||
}
|
||||
else if(opts['n'])
|
||||
{
|
||||
doprintf=true;
|
||||
newline=false;
|
||||
has_processed_options=true;
|
||||
// delete the number of args that were processed
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
in->args->args[0] = new arg("printf");
|
||||
if(possibly_expands(in->args->args[2]) )
|
||||
if(!(*it)->is_string() || (*it)->string().find('\\') != std::string::npos)
|
||||
{
|
||||
in->args->insert(1, new arg("%s\\ "));
|
||||
if(newline) // newline: add a newline command at the end
|
||||
has_escape_sequence=true;
|
||||
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);
|
||||
br->lst->add(new condlist(in));
|
||||
br->lst->add(make_condlist("echo"));
|
||||
pl->cmds[0] = br;
|
||||
if(enable_interpretation)
|
||||
format_str += "%b ";
|
||||
else
|
||||
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
|
||||
{
|
||||
std::string printfarg="'%s";
|
||||
for(uint32_t i=2; i<in->args->size(); i++)
|
||||
printfarg+=" %s";
|
||||
std::string format_str;
|
||||
if(enable_interpretation)
|
||||
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)
|
||||
printfarg+="\\n";
|
||||
printfarg+="'";
|
||||
in->args->insert(1, new arg(printfarg));
|
||||
{
|
||||
if(lst == nullptr)
|
||||
{
|
||||
lst = new list;
|
||||
lst->add(new condlist(in));
|
||||
}
|
||||
lst->add(make_condlist("echo"));
|
||||
}
|
||||
|
||||
if(lst != nullptr)
|
||||
{
|
||||
pl->cmds[0] = new brace(lst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -148,20 +148,47 @@ size_t cmd::arglist_size()
|
|||
|
||||
// string getters
|
||||
|
||||
bool arg::is_string()
|
||||
{
|
||||
return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
|
||||
}
|
||||
|
||||
std::string arg::string()
|
||||
{
|
||||
if(sa.size() != 1 || sa[0]->type != subarg::subarg_string)
|
||||
if(!this->is_string())
|
||||
return "";
|
||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||
}
|
||||
|
||||
std::string arg::first_sa_string()
|
||||
{
|
||||
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string)
|
||||
return "";
|
||||
if(sa.size() <=0 || sa[0]->type != _obj::subarg_string)
|
||||
return "";
|
||||
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> ret;
|
||||
|
|
|
|||
Loading…
Reference in a new issue