From 8b6a5767134f9217375ee4b09b5d6448653a619f Mon Sep 17 00:00:00 2001 From: zawz Date: Fri, 28 May 2021 16:31:17 +0200 Subject: [PATCH] improve echo debashifying --- include/struc.hpp | 7 +++ src/debashify.cpp | 143 +++++++++++++++++++++++++++++++------------ src/struc_helper.cpp | 33 +++++++++- 3 files changed, 140 insertions(+), 43 deletions(-) diff --git a/include/struc.hpp b/include/struc.hpp index 326495b..dabb156 100644 --- a/include/struc.hpp +++ b/include/struc.hpp @@ -187,11 +187,15 @@ public: std::vector 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 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); diff --git a/src/debashify.cpp b/src/debashify.cpp index fed43cc..9281b69 100644 --- a/src/debashify.cpp +++ b/src/debashify.cpp @@ -1,6 +1,6 @@ #include "debashify.hpp" -#include "ztd/options.hpp" +#include #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('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 args=in->args->strargs(1); std::vector 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; iargs->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; iargs->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; iargs->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; iargs->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); + } } } diff --git a/src/struc_helper.cpp b/src/struc_helper.cpp index cbeafdd..85235c1 100644 --- a/src/struc_helper.cpp +++ b/src/struc_helper.cpp @@ -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(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(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 arglist::strargs(uint32_t start) { std::vector ret;