Compare commits

..

39 commits

Author SHA1 Message Date
mateoferon
f74c97fc7f feat(bash): support bash time syntax 2022-12-09 16:57:20 +01:00
zawz
6453b44b00 chore(options): move -A option in help 2022-05-04 15:16:33 +02:00
zawz
f93447e7dc fix(parse): fix parse of sequential braces 2022-04-08 15:38:11 +02:00
zawz
0903cf41a1 chore(debashify): debashify procsub in redirects 2022-02-04 16:50:44 +01:00
zawz
8f0fd6f956 fix(bash): fix procsub redirect on block 2022-02-04 16:39:30 +01:00
zawz
bce1d4b455 feat(options): add --lxsh option to force lxsh parse 2022-02-04 15:17:13 +01:00
zawz
fe7e6cdb52 fix(minify): incorrectly escaped dollar on manip 2022-02-03 11:14:30 +01:00
zawz
b2c5aeea02 fix(exec): fix segfault on exec failure 2022-01-28 09:38:42 +01:00
zawz
d41ec0e3c6 tests: add empty quote dequote test 2022-01-28 09:38:13 +01:00
zawz
2024152dc6 fix(include): fix broken include on empty files 2022-01-24 14:46:48 +01:00
zawz
29f0fd91ad fix(minify)): fix removal of quote-only args 2022-01-19 17:41:25 +01:00
zawz
32b19a12fd chore: add tests 2021-12-20 15:59:42 +01:00
zawz
cdd03f28ac fix(debashify): error message on empty array create 2021-12-20 15:54:04 +01:00
zawz
8a64d4e207 fix(debashify): fix empty array debashify segfault 2021-12-20 15:53:38 +01:00
zawz
84ac0fa0ff fix(parse): fix broken bash array assign parse 2021-12-20 15:53:15 +01:00
zawwz
97da108d1a feat(minify): extend single-block minify 2021-12-10 16:24:46 +01:00
zawwz
d10be4116a fix(parse): fix incorrect parse of heredocuments on broken lists 2021-12-10 15:33:05 +01:00
zawz
0d56e6099d chore: increment version 2021-11-21 11:31:51 +01:00
zawz
0eb98c8c13 Merge branch 'dev' of github.com:zawwz/lxsh into dev 2021-11-21 11:29:37 +01:00
zawwz
78a768e98e fix(minify): fix subshell with backslash set as backtick 2021-11-09 16:26:14 +01:00
zawz
44c03ca0be fix debashify brace expansion segfault 2021-11-06 19:18:29 +01:00
zawwz
fab144947a internal: add obj recursive copy 2021-11-05 15:57:15 +01:00
zawwz
eac178e07a debashify brace expansions 2021-11-05 15:56:58 +01:00
zawwz
db3994f6d2 fix missing % arithmetic operator 2021-11-05 13:21:26 +01:00
zawwz
9dc7c12448 fix debug -J option 2021-11-05 11:32:11 +01:00
zawwz
39cc1da707 fix parsing of # in middle of arg 2021-11-05 10:52:48 +01:00
zawwz
a9e6b27ace fix arithmetic subarithmetic parse 2021-11-05 10:48:16 +01:00
zawwz
9a3086fc06 fix parenthesis arithmetic parsing 2021-11-05 10:27:47 +01:00
zawwz
0e9aa3b023 add map options 2021-11-03 14:37:49 +01:00
zawwz
92d4caf5c0 code cleanup 2021-11-03 11:41:42 +01:00
zawwz
6eb164fd58 update minify doc 2021-10-29 13:41:35 +02:00
zawwz
89160324cd bump version to 1.4 2021-10-29 13:29:24 +02:00
zawwz
e80ca9fb4c fix quote minify applying in heredocument 2021-10-28 13:34:24 +02:00
zawwz
cdf4ca5b85 minify escaped dollar 2021-10-28 13:33:46 +02:00
zawwz
0b46581b22 extend minify quotes to var assigns 2021-10-28 13:33:06 +02:00
zawz
2d0041e1ff fix broken heredocument 2021-10-20 17:30:11 +02:00
Mateo Feron
19fb7e8eac add IFS to reserved variables 2021-10-19 12:00:11 +02:00
Mateo Feron
abce171e94 extend minify: minify subshells to backticks 2021-10-14 15:39:52 +02:00
Mateo Feron
92d5f83b2f fix backtick parse 2021-10-14 15:21:30 +02:00
52 changed files with 2442 additions and 918 deletions

6
.gitignore vendored
View file

@ -1,10 +1,8 @@
/obj /obj
/test
/run-tests.sh
/Zmakefile /Zmakefile
/TODO TODO
/lxsh /lxsh
/gmon.out gmon.out
/profiling/* /profiling/*
/profiling.* /profiling.*
/include/g_* /include/g_*

View file

@ -45,7 +45,7 @@ These commands can be placed anywhere within the script like regular commands.
Reduce code size to a minimum without changing functionality with the `-m` option. Reduce code size to a minimum without changing functionality with the `-m` option.
> This option should be safe to use in any situation > This option should be safe to use in any situation, if this option changes behavior please report a bug
#### Behaviors of the minify option #### Behaviors of the minify option
@ -53,7 +53,9 @@ Reduce code size to a minimum without changing functionality with the `-m` optio
- removes `;;` from the last value in a case - removes `;;` from the last value in a case
- removes unnecessary quotes on arguments - removes unnecessary quotes on arguments
- transforms unnecessary manipulations (e.g. `${VAR}`) into simple variable call - transforms unnecessary manipulations (e.g. `${VAR}`) into simple variable call
- Brace blocks or subshells with a single command will be replaced by said command - brace blocks or subshells with a single command will be replaced by said command
- reduces level 1 `$()` subshells to use backticks
- escaped dollarsigns are un-escaped
> These features only apply if they won't change behavior, for instance > These features only apply if they won't change behavior, for instance
removal of an unnecessary manipulation will not be made if the following character removal of an unnecessary manipulation will not be made if the following character

View file

@ -2,12 +2,19 @@
#define MINIFY_HPP #define MINIFY_HPP
#include "struc.hpp" #include "struc.hpp"
#include "processing.hpp"
#include <regex> #include <regex>
#include <string> #include <string>
void minify_var(_obj* in, std::regex const& exclude); std::string gen_minmap(strmap_t const& map, std::string const& prefix);
void minify_fct(_obj* in, std::regex const& exclude); void read_minmap(std::string const& filepath, strmap_t* varmap, strmap_t* fctmap);
bool r_replace_fct(_obj* in, strmap_t* fctmap);
bool r_replace_var(_obj* in, strmap_t* varmap);
strmap_t minify_var(_obj* in, std::regex const& exclude);
strmap_t minify_fct(_obj* in, std::regex const& exclude);
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude); void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude);

View file

@ -11,7 +11,7 @@
#define SPACES " \t" #define SPACES " \t"
#define SEPARATORS " \t\n" #define SEPARATORS " \t\n"
#define ARG_END " \t\n;#()&|<>" #define ARG_END " \t\n;()&|<>"
#define VARNAME_END " \t\n;#()&|=\"'\\{}/-+" #define VARNAME_END " \t\n;#()&|=\"'\\{}/-+"
#define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\" #define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\"
#define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}" #define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}"
@ -32,7 +32,7 @@
#define ARG_OPTIMIZE_MANIP "$\\`}" #define ARG_OPTIMIZE_MANIP "$\\`}"
#define ARG_OPTIMIZE_DEFARR "$\\`)" #define ARG_OPTIMIZE_DEFARR "$\\`)"
#define ARG_OPTIMIZE_BASHTEST "$\\`] \t\n" #define ARG_OPTIMIZE_BASHTEST "$\\`] \t\n"
#define ARG_OPTIMIZE_ARG "$\\` \t\n;#()&|<>\"'" #define ARG_OPTIMIZE_ARG "$\\` \t\n;()&|<>\"'"
#define ARG_OPTIMIZE_ARRAY "$\\`\t\n&|}[]\"'" #define ARG_OPTIMIZE_ARRAY "$\\`\t\n&|}[]\"'"
#define ARG_OPTIMIZE_ALL "$\\` \t\n;#()&|<>}]\"'" #define ARG_OPTIMIZE_ALL "$\\` \t\n;#()&|<>}]\"'"
@ -97,35 +97,32 @@ inline uint32_t skip_unread_noline(parse_context const& ct) {
parse_context parse_heredocument(parse_context ctx); parse_context parse_heredocument(parse_context ctx);
// list // list
// std::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL); std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
// std::pair<list*, parse_context> parse_list_until(parse_context ct, std::string const& end_word);
// std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, std::vector<std::string> const& end_words, const char* expecting=NULL);
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
// name // name
std::pair<variable*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false); std::pair<variable_t*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
// subarg parsers // subarg parsers
std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ct); std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ct);
std::pair<variable*, parse_context> parse_manipulation(parse_context ct); std::pair<variable_t*, parse_context> parse_manipulation(parse_context ct);
// arg parser // arg parser
std::pair<arg*, parse_context> parse_arg(parse_context ct, const char* end=ARG_END, const char* unexpected=ARGLIST_END, bool doquote=true, const char* optimize=ARG_OPTIMIZE_ARG); std::pair<arg_t*, parse_context> parse_arg(parse_context ct, const char* end=ARG_END, const char* unexpected=ARGLIST_END, bool doquote=true, const char* optimize=ARG_OPTIMIZE_ARG);
// redirect parser // redirect parser
std::pair<redirect*, parse_context> parse_redirect(parse_context ct); std::pair<redirect_t*, parse_context> parse_redirect(parse_context ct);
// arglist parser // arglist parser
std::pair<arglist*, parse_context> parse_arglist(parse_context ct, bool hard_error=false, std::vector<redirect*>* redirs=nullptr); std::pair<arglist_t*, parse_context> parse_arglist(parse_context ct, bool hard_error=false, std::vector<redirect_t*>* redirs=nullptr, bool stop_on_brace=false);
// block parsers // block parsers
std::pair<block*, parse_context> parse_block(parse_context ct); std::pair<block_t*, parse_context> parse_block(parse_context ct);
std::pair<cmd*, parse_context> parse_cmd(parse_context ct); std::pair<cmd_t*, parse_context> parse_cmd(parse_context ct);
std::pair<function*, parse_context> parse_function(parse_context ct, const char* after="()"); std::pair<function_t*, parse_context> parse_function(parse_context ct, const char* after="()");
std::pair<subshell*, parse_context> parse_subshell(parse_context ct); std::pair<subshell_t*, parse_context> parse_subshell(parse_context ct);
std::pair<brace*, parse_context> parse_brace(parse_context ct); std::pair<brace_t*, parse_context> parse_brace(parse_context ct);
std::pair<case_block*, parse_context> parse_case(parse_context ct); std::pair<case_t*, parse_context> parse_case(parse_context ct);
std::pair<if_block*, parse_context> parse_if(parse_context ct); std::pair<if_t*, parse_context> parse_if(parse_context ct);
std::pair<for_block*, parse_context> parse_for(parse_context ct); std::pair<for_t*, parse_context> parse_for(parse_context ct);
std::pair<while_block*, parse_context> parse_while(parse_context ct); std::pair<while_t*, parse_context> parse_while(parse_context ct);
// pipeline parser // pipeline parser
std::pair<pipeline*, parse_context> parse_pipeline(parse_context ct); std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ct);
// condlist parser // condlist parser
std::pair<condlist*, parse_context> parse_condlist(parse_context ct); std::pair<condlist_t*, parse_context> parse_condlist(parse_context ct);
#endif //PARSE_HPP #endif //PARSE_HPP

View file

@ -9,7 +9,7 @@
#include "struc.hpp" #include "struc.hpp"
// constants // constants
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR" #define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR", "IFS"
// types // types
typedef std::map<std::string,uint32_t> countmap_t; typedef std::map<std::string,uint32_t> countmap_t;
@ -60,7 +60,7 @@ std::regex fct_exclude_regex(std::string const& in);
// varnames // varnames
bool is_varname(std::string const& in); bool is_varname(std::string const& in);
std::string get_varname(std::string const& in); std::string get_varname(std::string const& in);
std::string get_varname(arg* in); std::string get_varname(arg_t* in);
// list objects // list objects
void list_map(countmap_t const& map); void list_map(countmap_t const& map);

View file

@ -19,68 +19,58 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
// recursive calls // recursive calls
switch(o->type) switch(o->type)
{ {
case _obj::_variable : case _obj::variable :
{ {
variable* t = dynamic_cast<variable*>(o); variable_t* t = dynamic_cast<variable_t*>(o);
recurse(fct, t->index, args...); recurse(fct, t->index, args...);
recurse(fct, t->manip, args...); recurse(fct, t->manip, args...);
break; break;
} }
case _obj::_redirect : case _obj::redirect :
{ {
redirect* t = dynamic_cast<redirect*>(o); redirect_t* t = dynamic_cast<redirect_t*>(o);
recurse(fct, t->target, args...); recurse(fct, t->target, args...);
recurse(fct, t->here_document, args...); recurse(fct, t->here_document, args...);
break; break;
} }
case _obj::_arg : case _obj::arg :
{ {
arg* t = dynamic_cast<arg*>(o); arg_t* t = dynamic_cast<arg_t*>(o);
for(auto it: t->sa) for(auto it: t->sa)
{
recurse(fct, it, args...); recurse(fct, it, args...);
}
break; break;
} }
case _obj::_arglist : case _obj::arglist :
{ {
arglist* t = dynamic_cast<arglist*>(o); arglist_t* t = dynamic_cast<arglist_t*>(o);
for(auto it: t->args) for(auto it: t->args)
{
recurse(fct, it, args...); recurse(fct, it, args...);
}
break; break;
} }
case _obj::_pipeline : case _obj::pipeline :
{ {
pipeline* t = dynamic_cast<pipeline*>(o); pipeline_t* t = dynamic_cast<pipeline_t*>(o);
for(auto it: t->cmds) for(auto it: t->cmds)
{
recurse(fct, it, args...); recurse(fct, it, args...);
}
break; break;
} }
case _obj::_condlist : case _obj::condlist :
{ {
condlist* t = dynamic_cast<condlist*>(o); condlist_t* t = dynamic_cast<condlist_t*>(o);
for(auto it: t->pls) for(auto it: t->pls)
{
recurse(fct, it, args...); recurse(fct, it, args...);
}
break; break;
} }
case _obj::_list : case _obj::list :
{ {
list* t = dynamic_cast<list*>(o); list_t* t = dynamic_cast<list_t*>(o);
for(auto it: t->cls) for(auto it: t->cls)
{
recurse(fct, it, args...); recurse(fct, it, args...);
}
break; break;
} }
case _obj::block_subshell : case _obj::block_subshell :
{ {
subshell* t = dynamic_cast<subshell*>(o); subshell_t* t = dynamic_cast<subshell_t*>(o);
recurse(fct, t->lst, args...); recurse(fct, t->lst, args...);
for(auto it: t->redirs) for(auto it: t->redirs)
@ -90,7 +80,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_brace : case _obj::block_brace :
{ {
brace* t = dynamic_cast<brace*>(o); brace_t* t = dynamic_cast<brace_t*>(o);
recurse(fct, t->lst, args...); recurse(fct, t->lst, args...);
for(auto it: t->redirs) for(auto it: t->redirs)
@ -110,7 +100,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_function : case _obj::block_function :
{ {
function* t = dynamic_cast<function*>(o); function_t* t = dynamic_cast<function_t*>(o);
recurse(fct, t->lst, args...); recurse(fct, t->lst, args...);
for(auto it: t->redirs) for(auto it: t->redirs)
@ -120,7 +110,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_cmd : case _obj::block_cmd :
{ {
cmd* t = dynamic_cast<cmd*>(o); cmd_t* t = dynamic_cast<cmd_t*>(o);
recurse(fct, t->args, args...); recurse(fct, t->args, args...);
for(auto it: t->var_assigns) for(auto it: t->var_assigns)
{ {
@ -140,7 +130,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_case : case _obj::block_case :
{ {
case_block* t = dynamic_cast<case_block*>(o); case_t* t = dynamic_cast<case_t*>(o);
// carg // carg
recurse(fct, t->carg, args...); recurse(fct, t->carg, args...);
// cases // cases
@ -160,7 +150,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_if : case _obj::block_if :
{ {
if_block* t = dynamic_cast<if_block*>(o); if_t* t = dynamic_cast<if_t*>(o);
// ifs // ifs
for(auto sc: t->blocks) for(auto sc: t->blocks)
{ {
@ -179,7 +169,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_for : case _obj::block_for :
{ {
for_block* t = dynamic_cast<for_block*>(o); for_t* t = dynamic_cast<for_t*>(o);
// variable // variable
recurse(fct, t->var, args...); recurse(fct, t->var, args...);
// iterations // iterations
@ -194,7 +184,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::block_while : case _obj::block_while :
{ {
while_block* t = dynamic_cast<while_block*>(o); while_t* t = dynamic_cast<while_t*>(o);
// condition // condition
recurse(fct, t->cond, args...); recurse(fct, t->cond, args...);
// operations // operations
@ -207,50 +197,50 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
case _obj::subarg_variable : case _obj::subarg_variable :
{ {
variable_subarg* t = dynamic_cast<variable_subarg*>(o); subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
recurse(fct, t->var, args...); recurse(fct, t->var, args...);
break; break;
} }
case _obj::subarg_subshell : case _obj::subarg_subshell :
{ {
subshell_subarg* t = dynamic_cast<subshell_subarg*>(o); subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
recurse(fct, t->sbsh, args...); recurse(fct, t->sbsh, args...);
break; break;
} }
case _obj::subarg_procsub : case _obj::subarg_procsub :
{ {
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o); subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
recurse(fct, t->sbsh, args...); recurse(fct, t->sbsh, args...);
break; break;
} }
case _obj::subarg_arithmetic : case _obj::subarg_arithmetic :
{ {
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o); subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
recurse(fct, t->arith, args...); recurse(fct, t->arith, args...);
break; break;
} }
case _obj::arithmetic_variable : case _obj::arithmetic_variable :
{ {
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o); arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
recurse(fct, t->var, args...); recurse(fct, t->var, args...);
break; break;
} }
case _obj::arithmetic_subshell : case _obj::arithmetic_subshell :
{ {
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o); arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
recurse(fct, t->sbsh, args...); recurse(fct, t->sbsh, args...);
break; break;
} }
case _obj::arithmetic_operation : case _obj::arithmetic_operation :
{ {
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o); arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
recurse(fct, t->val1, args...); recurse(fct, t->val1, args...);
recurse(fct, t->val2, args...); recurse(fct, t->val2, args...);
break; break;
} }
case _obj::arithmetic_parenthesis : case _obj::arithmetic_parenthesis :
{ {
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o); arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
recurse(fct, t->val, args...); recurse(fct, t->val, args...);
break; break;
} }
@ -259,5 +249,292 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
} }
} }
// deep copy of object structure
template<class... Args>
_obj* obj_copy(_obj* o)
{
if(o == nullptr)
return nullptr;
// recursive calls
switch(o->type)
{
case _obj::variable :
{
variable_t* t = dynamic_cast<variable_t*>(o);
variable_t* ret = new variable_t(*t);
ret->index = dynamic_cast<arg_t*>(obj_copy(t->index));
ret->manip = dynamic_cast<arg_t*>(obj_copy(t->manip));
return ret;
}
case _obj::redirect :
{
redirect_t* t = dynamic_cast<redirect_t*>(o);
redirect_t* ret = new redirect_t(*t);
ret->target = dynamic_cast<arg_t*>(obj_copy(t->target));
ret->here_document = dynamic_cast<arg_t*>(obj_copy(t->here_document));
return ret;
}
case _obj::arg :
{
arg_t* t = dynamic_cast<arg_t*>(o);
arg_t* ret = new arg_t(*t);
for(uint32_t i=0; i<ret->sa.size(); i++)
ret->sa[i] = dynamic_cast<subarg_t*>(obj_copy(t->sa[i]));
return ret;
}
case _obj::arglist :
{
arglist_t* t = dynamic_cast<arglist_t*>(o);
arglist_t* ret = new arglist_t(*t);
for(uint32_t i=0; i<ret->args.size(); i++)
ret->args[i] = dynamic_cast<arg_t*>(obj_copy(t->args[i]));
return ret;
}
case _obj::pipeline :
{
pipeline_t* t = dynamic_cast<pipeline_t*>(o);
pipeline_t* ret = new pipeline_t(*t);
for(uint32_t i=0; i<ret->cmds.size(); i++)
ret->cmds[i] = dynamic_cast<block_t*>(obj_copy(t->cmds[i]));
return ret;
}
case _obj::condlist :
{
condlist_t* t = dynamic_cast<condlist_t*>(o);
condlist_t* ret = new condlist_t(*t);
for(uint32_t i=0; i<ret->pls.size(); i++)
ret->pls[i] = dynamic_cast<pipeline_t*>(obj_copy(t->pls[i]));
return ret;
}
case _obj::list :
{
list_t* t = dynamic_cast<list_t*>(o);
list_t* ret = new list_t(*t);
for(uint32_t i=0; i<ret->cls.size(); i++)
ret->cls[i] = dynamic_cast<condlist_t*>(obj_copy(t->cls[i]));
return ret;
}
case _obj::block_subshell :
{
subshell_t* t = dynamic_cast<subshell_t*>(o);
subshell_t* ret = new subshell_t(*t);
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_brace :
{
brace_t* t = dynamic_cast<brace_t*>(o);
brace_t* ret = new brace_t(*t);
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_main :
{
shmain* t = dynamic_cast<shmain*>(o);
shmain* ret = new shmain(*t);
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_function :
{
function_t* t = dynamic_cast<function_t*>(o);
function_t* ret = new function_t(*t);
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_cmd :
{
cmd_t* t = dynamic_cast<cmd_t*>(o);
cmd_t* ret = new cmd_t(*t);
ret->args = dynamic_cast<arglist_t*>(obj_copy(t->args));
for(uint32_t i=0; i<ret->var_assigns.size(); i++)
{
ret->var_assigns[i].first = dynamic_cast<variable_t*>(obj_copy(t->var_assigns[i].first));
ret->var_assigns[i].second = dynamic_cast<arg_t*>(obj_copy(t->var_assigns[i].second));
}
for(uint32_t i=0; i<ret->cmd_var_assigns.size(); i++)
{
ret->cmd_var_assigns[i].first = dynamic_cast<variable_t*>(obj_copy(t->cmd_var_assigns[i].first));
ret->cmd_var_assigns[i].second = dynamic_cast<arg_t*>(obj_copy(t->cmd_var_assigns[i].second));
}
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_case :
{
case_t* t = dynamic_cast<case_t*>(o);
case_t* ret = new case_t(*t);
// carg
ret->carg = dynamic_cast<arg_t*>(obj_copy(t->carg));
// cases
for(uint32_t i=0; i<ret->cases.size(); i++)
{
for(uint32_t j=0; j<ret->cases[i].first.size(); i++)
ret->cases[i].first[j] = dynamic_cast<arg_t*>(obj_copy(t->cases[i].first[j]));
ret->cases[i].second = dynamic_cast<list_t*>(obj_copy(t->cases[i].second));
}
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_if :
{
if_t* t = dynamic_cast<if_t*>(o);
if_t* ret = new if_t(*t);
// ifs
for(uint32_t i=0; i<ret->blocks.size(); i++)
{
// condition
ret->blocks[i].first = dynamic_cast<list_t*>(obj_copy(t->blocks[i].first));
// execution
ret->blocks[i].second = dynamic_cast<list_t*>(obj_copy(t->blocks[i].second));
}
// else
ret->else_lst = dynamic_cast<list_t*>(obj_copy(t->else_lst));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_for :
{
for_t* t = dynamic_cast<for_t*>(o);
for_t* ret = new for_t(*t);
// variable
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
// iterations
ret->iter = dynamic_cast<arglist_t*>(obj_copy(t->iter));
// for block
ret->ops = dynamic_cast<list_t*>(obj_copy(t->ops));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::block_while :
{
while_t* t = dynamic_cast<while_t*>(o);
while_t* ret = new while_t(*t);
// condition
ret->cond = dynamic_cast<list_t*>(obj_copy(t->cond));
// for operations
ret->ops = dynamic_cast<list_t*>(obj_copy(t->ops));
for(uint32_t i=0; i<ret->redirs.size(); i++)
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
return ret;
}
case _obj::subarg_string :
{
subarg_string_t* t = dynamic_cast<subarg_string_t*>(o);
subarg_string_t* ret = new subarg_string_t(*t);
return ret;
}
case _obj::subarg_variable :
{
subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
subarg_variable_t* ret = new subarg_variable_t(*t);
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
return ret;
}
case _obj::subarg_subshell :
{
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
subarg_subshell_t* ret = new subarg_subshell_t(*t);
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
return ret;
}
case _obj::subarg_procsub :
{
subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
subarg_procsub_t* ret = new subarg_procsub_t(*t);
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
return ret;
}
case _obj::subarg_arithmetic :
{
subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
subarg_arithmetic_t* ret = new subarg_arithmetic_t(*t);
ret->arith = dynamic_cast<arithmetic_t*>(obj_copy(t->arith));
return ret;
}
case _obj::arithmetic_number :
{
arithmetic_number_t* t = dynamic_cast<arithmetic_number_t*>(o);
arithmetic_number_t* ret = new arithmetic_number_t(*t);
return ret;
}
case _obj::arithmetic_variable :
{
arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
arithmetic_variable_t* ret = new arithmetic_variable_t(*t);
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
return ret;
}
case _obj::arithmetic_subshell :
{
arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
arithmetic_subshell_t* ret = new arithmetic_subshell_t(*t);
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
return ret;
}
case _obj::arithmetic_operation :
{
arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
arithmetic_operation_t* ret = new arithmetic_operation_t(*t);
ret->val1 = dynamic_cast<arithmetic_t*>(obj_copy(t->val1));
ret->val2 = dynamic_cast<arithmetic_t*>(obj_copy(t->val2));
return ret;
}
case _obj::arithmetic_parenthesis :
{
arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
arithmetic_parenthesis_t* ret = new arithmetic_parenthesis_t(*t);
ret->val = dynamic_cast<arithmetic_t*>(obj_copy(t->val));
return ret;
}
default: return nullptr; //dummy
}
}
#endif //RECURSIVE_HPP #endif //RECURSIVE_HPP

View file

@ -6,8 +6,8 @@
extern std::vector<std::string> included; extern std::vector<std::string> included;
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, parse_context ctx, std::string* ex_dir=nullptr); std::vector<std::pair<std::string, std::string>> do_include_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir=nullptr);
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, parse_context ctx, std::string* ex_dir=nullptr); std::pair<std::string, std::string> do_resolve_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir=nullptr);
bool add_include(std::string const& file); bool add_include(std::string const& file);

View file

@ -67,13 +67,13 @@ subarg: can be one of
#define AND_OP false #define AND_OP false
#define OR_OP true #define OR_OP true
class condlist; class condlist_t;
class block; class block_t;
class pipeline; class pipeline_t;
class arg; class arg_t;
class subarg; class subarg_t;
class cmd; class cmd_t;
class redirect; class redirect_t;
// structs // structs
@ -88,12 +88,12 @@ struct parse_context {
const char* here_doc=""; const char* here_doc="";
const char operator[](uint64_t a) { return data[a]; } const char operator[](uint64_t a) { return data[a]; }
bool has_errored=false; bool has_errored=false;
redirect* here_document=nullptr; redirect_t* here_document=nullptr;
char* here_delimitor=NULL; char* here_delimitor=NULL;
}; };
struct generate_context { struct generate_context {
arg* here_document=nullptr; arg_t* here_document=nullptr;
}; };
// exceptions // exceptions
@ -124,24 +124,19 @@ private:
// objects // objects
// type pack of condlist
typedef std::vector<arg*> arglist_t;
extern std::string g_origin;
// meta object type // meta object type
class _obj class _obj
{ {
public: public:
enum _objtype { enum _objtype {
subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_procsub, subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_procsub,
_variable, variable,
_redirect, redirect,
_arg, arg,
_arglist, arglist,
_pipeline, pipeline,
_condlist, condlist,
_list, list,
arithmetic_operation, arithmetic_number, arithmetic_variable, arithmetic_parenthesis, arithmetic_subshell, arithmetic_operation, arithmetic_number, arithmetic_variable, arithmetic_parenthesis, arithmetic_subshell,
block_subshell, block_brace, block_main, block_cmd, block_function, block_case, block_if, block_for, block_while }; block_subshell, block_brace, block_main, block_cmd, block_function, block_case, block_if, block_for, block_while };
_objtype type; _objtype type;
@ -151,41 +146,44 @@ public:
}; };
// meta arithmetic type // meta arithmetic type
class arithmetic : public _obj class arithmetic_t : public _obj
{ {
public: public:
virtual std::string generate(int ind)=0; virtual std::string generate(int ind)=0;
}; };
// meta subarg type // meta subarg type
class subarg : public _obj class subarg_t : public _obj
{ {
public: public:
virtual ~subarg() {;} virtual ~subarg_t() {;}
virtual std::string generate(int ind)=0; virtual std::string generate(int ind)=0;
bool quoted; bool quoted;
}; };
class arg : public _obj class arg_t : public _obj
{ {
public: public:
arg() { type=_obj::_arg; } arg_t() { type=_obj::arg; forcequoted=false; }
arg(std::string const& str) { type=_obj::_arg; this->set(str);} arg_t(std::string const& str, bool fquote=false) { type=_obj::arg; this->set(str); forcequoted=fquote; }
arg(subarg* in) { type=_obj::_arg; sa.push_back(in); } arg_t(subarg_t* in, bool fquote=false) { type=_obj::arg; sa.push_back(in); forcequoted=fquote; }
~arg() { for(auto it: sa) delete it; } ~arg_t() { for(auto it: sa) delete it; }
void set(std::string const& str); void set(std::string const& str);
void insert(uint32_t i, subarg* val); void insert(uint32_t i, subarg_t* val);
void insert(uint32_t i, arg const& a); void insert(uint32_t i, arg_t const& a);
void insert(uint32_t i, std::string const& in); void insert(uint32_t i, std::string const& in);
inline void add(subarg* in) { sa.push_back(in); } inline void add(subarg_t* in) { sa.push_back(in); }
void add(std::string const& in); void add(std::string const& in);
inline size_t size() { return sa.size(); } inline size_t size() { return sa.size(); }
std::vector<subarg*> sa; std::vector<subarg_t*> sa;
// is forcequoted: var assign
bool forcequoted;
bool is_string(); bool is_string();
// return if is a string and only one subarg // return if is a string and only one subarg
@ -201,59 +199,61 @@ public:
std::string generate(int ind); std::string generate(int ind);
}; };
class variable : public _obj class variable_t : public _obj
{ {
public: public:
variable(std::string const& in="", arg* i=nullptr, bool def=false, bool ismanip=false, arg* m=nullptr) { type=_obj::_variable; varname=in; index=i; definition=def; is_manip=ismanip; precedence=false; manip=m; } variable_t(std::string const& in="", arg_t* i=nullptr, bool def=false, bool ismanip=false, arg_t* m=nullptr) { type=_obj::variable; varname=in; index=i; definition=def; is_manip=ismanip; precedence=false; manip=m; }
~variable() { ~variable_t() {
if(index!=nullptr) delete index; if(index!=nullptr) delete index;
if(manip!=nullptr) delete manip; if(manip!=nullptr) delete manip;
} }
std::string varname; std::string varname;
bool definition; bool definition;
arg* index; // for bash specific arg_t* index; // for bash specific
bool is_manip; bool is_manip;
bool precedence; bool precedence;
arg* manip; arg_t* manip;
std::string generate(int ind); std::string generate(int ind);
}; };
// arglist // arglist
class arglist : public _obj class arglist_t : public _obj
{ {
public: public:
arglist() { type=_obj::_arglist; } arglist_t() { type=_obj::arglist; }
arglist(arg* in) { type=_obj::_arglist; this->add(in); } arglist_t(arg_t* in) { type=_obj::arglist; this->add(in); }
~arglist() { for( auto it: args ) delete it; } ~arglist_t() { for( auto it: args ) delete it; }
inline void add(arg* in) { args.push_back(in); } inline void add(arg_t* in) { args.push_back(in); }
std::vector<arg*> args; std::vector<arg_t*> args;
std::vector<std::string> strargs(uint32_t start); std::vector<std::string> strargs(uint32_t start);
// get first argument as string
std::string first_arg_string();
// potentially expands into more arguments than its size // potentially expands into more arguments than its size
bool can_expand(); bool can_expand();
void insert(uint32_t i, arg* val); void insert(uint32_t i, arg_t* val);
void insert(uint32_t i, arglist const& lst); void insert(uint32_t i, arglist_t const& lst);
inline size_t size() { return args.size(); } inline size_t size() { return args.size(); }
std::string generate(int ind); std::string generate(int ind);
}; };
class redirect : public _obj class redirect_t : public _obj
{ {
public: public:
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; here_document=nullptr; } redirect_t(std::string strop="") { type=_obj::redirect; op=strop; target=nullptr; here_document=nullptr; }
redirect(arg* in) { type=_obj::_redirect; target=in; here_document=nullptr; } redirect_t(arg_t* in) { type=_obj::redirect; target=in; here_document=nullptr; }
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; here_document=nullptr; } redirect_t(std::string strop, arg_t* in) { type=_obj::redirect; op=strop; target=in; here_document=nullptr; }
redirect(std::string strop, arg* in, arg* doc) { type=_obj::_redirect; op=strop; target=in; here_document=doc; } redirect_t(std::string strop, arg_t* in, arg_t* doc) { type=_obj::redirect; op=strop; target=in; here_document=doc; }
~redirect() { ~redirect_t() {
if(target != nullptr) delete target; if(target != nullptr) delete target;
if(here_document != nullptr) delete here_document; if(here_document != nullptr) delete here_document;
} }
@ -261,21 +261,21 @@ public:
std::string generate(int ind); std::string generate(int ind);
std::string op; std::string op;
arg* target; arg_t* target;
arg* here_document; arg_t* here_document;
}; };
// Meta block // Meta block
class block : public _obj class block_t : public _obj
{ {
public: public:
block() { ; } block_t() { ; }
virtual ~block() { for(auto it: redirs) delete it; } virtual ~block_t() { for(auto it: redirs) delete it; }
// cmd // cmd
std::vector<redirect*> redirs; std::vector<redirect_t*> redirs;
// subshell: return the containing cmd, if it is a single command // subshell: return the containing cmd, if it is a single command
cmd* single_cmd(); cmd_t* single_cmd();
std::string generate_redirs(int ind, std::string const& _str, generate_context* ctx); std::string generate_redirs(int ind, std::string const& _str, generate_context* ctx);
@ -284,15 +284,16 @@ public:
// PL // PL
class pipeline : public _obj class pipeline_t : public _obj
{ {
public: public:
pipeline(block* bl=nullptr) { type=_obj::_pipeline; if(bl!=nullptr) cmds.push_back(bl); negated=false; } pipeline_t(block_t* bl=nullptr) { type=_obj::pipeline; if(bl!=nullptr) cmds.push_back(bl); negated=false; bash_time=false; }
~pipeline() { for(auto it: cmds) delete it; } ~pipeline_t() { for(auto it: cmds) delete it; }
inline void add(block* bl) { this->cmds.push_back(bl); } inline void add(block_t* bl) { this->cmds.push_back(bl); }
std::vector<block*> cmds; std::vector<block_t*> cmds;
bool negated; // negated return value (! at start) bool negated; // negated return value (! at start)
bool bash_time; // has bash time command
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); }; std::string generate(int ind) { return this->generate(ind, nullptr); };
@ -300,49 +301,49 @@ public:
// CL // CL
class condlist : public _obj class condlist_t : public _obj
{ {
public: public:
condlist() { type=_obj::_condlist; parallel=false; } condlist_t() { type=_obj::condlist; parallel=false; }
condlist(pipeline* pl) { type=_obj::_condlist; parallel=false; this->add(pl); } condlist_t(pipeline_t* pl) { type=_obj::condlist; parallel=false; this->add(pl); }
condlist(block* bl); condlist_t(block_t* bl);
~condlist() { for(auto it: pls) delete it; } ~condlist_t() { for(auto it: pls) delete it; }
bool parallel; // & at the end bool parallel; // & at the end
void add(pipeline* pl, bool or_op=false); void add(pipeline_t* pl, bool or_op=false);
// don't push_back here, use add() instead // don't push_back here, use add() instead
std::vector<pipeline*> pls; std::vector<pipeline_t*> pls;
std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines
void prune_first_cmd(); void prune_first_cmd();
block* first_block(); block_t* first_block();
cmd* first_cmd(); cmd_t* first_cmd();
cmd* get_cmd(std::string const& cmdname); cmd_t* get_cmd(std::string const& cmdname);
void negate(); void negate();
std::string generate(int ind); std::string generate(int ind);
}; };
class list : public _obj class list_t : public _obj
{ {
public: public:
list() { type=_obj::_list; } list_t() { type=_obj::list; }
list(condlist* in) { type=_obj::_list; this->add(in); } list_t(condlist_t* in) { type=_obj::list; this->add(in); }
~list() { for(auto it: cls) delete it; } ~list_t() { for(auto it: cls) delete it; }
void clear() { for(auto it: cls) delete it; cls.resize(0); } void clear() { for(auto it: cls) delete it; cls.resize(0); }
std::vector<condlist*> cls; std::vector<condlist_t*> cls;
inline void add(condlist* in) { cls.push_back(in); } inline void add(condlist_t* in) { cls.push_back(in); }
condlist* last_cond() { return cls[cls.size()-1]; } condlist_t* last_cond() { return cls[cls.size()-1]; }
void insert(uint32_t i, condlist* val); void insert(uint32_t i, condlist_t* val);
void insert(uint32_t i, list const& lst); void insert(uint32_t i, list_t const& lst);
size_t size() { return cls.size(); } size_t size() { return cls.size(); }
@ -350,22 +351,13 @@ public:
std::string generate(int ind) { return this->generate(ind, true); } std::string generate(int ind) { return this->generate(ind, true); }
}; };
// class redir
// {
// public:
// enum redirtype { none, write, append, read, raw } ;
// redir(redirtype in=none) { type=in; }
// redirtype type;
// arg val;
// };
// block subtypes // // block subtypes //
class cmd : public block class cmd_t : public block_t
{ {
public: public:
cmd(arglist* in=nullptr) { type=_obj::block_cmd; args=in; is_cmdvar=false; } cmd_t(arglist_t* in=nullptr) { type=_obj::block_cmd; args=in; is_cmdvar=false; }
~cmd() { ~cmd_t() {
if(args!=nullptr) delete args; if(args!=nullptr) delete args;
for(auto it: var_assigns) { for(auto it: var_assigns) {
delete it.first; delete it.first;
@ -383,36 +375,36 @@ public:
size_t arglist_size(); size_t arglist_size();
void add(arg* in); void add(arg_t* in);
// preceding var assigns // preceding var assigns
std::vector<std::pair<variable*,arg*>> var_assigns; std::vector<std::pair<variable_t*,arg_t*>> var_assigns;
// is a cmdvar type // is a cmdvar type
bool is_cmdvar; bool is_cmdvar;
// var assigns on cmdvar // var assigns on cmdvar
std::vector<std::pair<variable*,arg*>> cmd_var_assigns; std::vector<std::pair<variable_t*,arg_t*>> cmd_var_assigns;
// check if cmd is this (ex: unset) // check if cmd is this (ex: unset)
bool is(std::string const& in); bool is(std::string const& in);
// for var assigns in special cmds (export, unset, read, local) // for var assigns in special cmds (export, unset, read, local)
bool is_argvar(); bool is_argvar();
std::vector<subarg*> subarg_vars(); std::vector<subarg_t*> subarg_vars();
// returns true if command performs env var changes // returns true if command performs env var changes
bool has_var_assign(); bool has_var_assign();
arglist* args; arglist_t* args;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class shmain : public block class shmain : public block_t
{ {
public: public:
shmain(list* in=nullptr) { type=_obj::block_main; lst=in; } shmain(list_t* in=nullptr) { type=_obj::block_main; if(in == nullptr) lst = new list_t; else lst=in; }
~shmain() { ~shmain() {
if(lst!=nullptr) delete lst; if(lst!=nullptr) delete lst;
} }
@ -421,66 +413,66 @@ public:
std::string filename; std::string filename;
std::string shebang; std::string shebang;
list* lst; list_t* lst;
std::string generate(bool print_shebang=true, int ind=0); std::string generate(bool print_shebang=true, int ind=0);
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class subshell : public block class subshell_t : public block_t
{ {
public: public:
subshell(list* in=nullptr) { type=_obj::block_subshell; lst=in; } subshell_t(list_t* in=nullptr) { type=_obj::block_subshell; lst=in; }
subshell(block* in) { type=_obj::block_subshell; lst=new list(new condlist(in)); } subshell_t(block_t* in) { type=_obj::block_subshell; lst=new list_t(new condlist_t(in)); }
~subshell() { ~subshell_t() {
if(lst!=nullptr) delete lst; if(lst!=nullptr) delete lst;
} }
cmd* single_cmd(); cmd_t* single_cmd();
list* lst; list_t* lst;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class brace : public block class brace_t : public block_t
{ {
public: public:
brace(list* in=nullptr) { type=_obj::block_brace; lst=in; } brace_t(list_t* in=nullptr) { type=_obj::block_brace; lst=in; }
~brace() { ~brace_t() {
if(lst!=nullptr) delete lst; if(lst!=nullptr) delete lst;
} }
cmd* single_cmd(); cmd_t* single_cmd();
list* lst; list_t* lst;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class function : public block class function_t : public block_t
{ {
public: public:
function(list* in=nullptr) { type=_obj::block_function; lst=in; } function_t(list_t* in=nullptr) { type=_obj::block_function; lst=in; }
~function() { ~function_t() {
if(lst!=nullptr) delete lst; if(lst!=nullptr) delete lst;
} }
std::string name; std::string name;
list* lst; list_t* lst;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class case_block : public block class case_t : public block_t
{ {
public: public:
case_block(arg* in=nullptr) { type=_obj::block_case; carg=in; } case_t(arg_t* in=nullptr) { type=_obj::block_case; carg=in; }
~case_block() { ~case_t() {
if(carg!=nullptr) delete carg; if(carg!=nullptr) delete carg;
for( auto cit : cases ) for( auto cit : cases )
{ {
@ -490,18 +482,18 @@ public:
} }
} }
arg* carg; arg_t* carg;
std::vector< std::pair<std::vector<arg*>, list*> > cases; std::vector< std::pair<std::vector<arg_t*>, list_t*> > cases;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class if_block : public block class if_t : public block_t
{ {
public: public:
if_block() { type=_obj::block_if; else_lst=nullptr; } if_t() { type=_obj::block_if; else_lst=nullptr; }
~if_block() { ~if_t() {
for(auto ifb: blocks) for(auto ifb: blocks)
{ {
if(ifb.first!=nullptr) delete ifb.first; if(ifb.first!=nullptr) delete ifb.first;
@ -510,28 +502,28 @@ public:
if(else_lst!=nullptr) delete else_lst; if(else_lst!=nullptr) delete else_lst;
} }
std::vector< std::pair<list*,list*> > blocks; std::vector< std::pair<list_t*,list_t*> > blocks;
list* else_lst; list_t* else_lst;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class for_block : public block class for_t : public block_t
{ {
public: public:
for_block(variable* in=nullptr, arglist* args=nullptr, list* lst=nullptr, bool ii=false) { type=_obj::block_for; var=in; iter=args; ops=lst; in_val=ii; } for_t(variable_t* in=nullptr, arglist_t* args=nullptr, list_t* lst=nullptr, bool ii=false) { type=_obj::block_for; var=in; iter=args; ops=lst; in_val=ii; }
~for_block() { ~for_t() {
if(iter!=nullptr) delete iter; if(iter!=nullptr) delete iter;
if(ops!=nullptr) delete ops; if(ops!=nullptr) delete ops;
if(var!=nullptr) delete var; if(var!=nullptr) delete var;
} }
variable* var; variable_t* var;
arglist* iter; arglist_t* iter;
list* ops; list_t* ops;
bool in_val; bool in_val;
@ -539,19 +531,19 @@ public:
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
}; };
class while_block : public block class while_t : public block_t
{ {
public: public:
while_block(list* a=nullptr, list* b=nullptr) { type=_obj::block_while; cond=a; ops=b; } while_t(list_t* a=nullptr, list_t* b=nullptr) { type=_obj::block_while; cond=a; ops=b; }
~while_block() { ~while_t() {
if(cond!=nullptr) delete cond; if(cond!=nullptr) delete cond;
if(ops!=nullptr) delete ops; if(ops!=nullptr) delete ops;
} }
condlist* real_condition() { return cond->last_cond(); } condlist_t* real_condition() { return cond->last_cond(); }
list* cond; list_t* cond;
list* ops; list_t* ops;
std::string generate(int ind, generate_context* ctx); std::string generate(int ind, generate_context* ctx);
std::string generate(int ind) { return this->generate(ind, nullptr); } std::string generate(int ind) { return this->generate(ind, nullptr); }
@ -559,129 +551,130 @@ public:
// Subarg subtypes // // Subarg subtypes //
class string_subarg : public subarg class subarg_string_t : public subarg_t
{ {
public: public:
string_subarg(std::string const& in="") { type=_obj::subarg_string; val=in; } subarg_string_t(std::string const& in="") { type=_obj::subarg_string; val=in; }
~string_subarg() {;} ~subarg_string_t() {;}
std::string val; std::string val;
std::string generate(int ind) { return val; } std::string generate(int ind) { return val; }
}; };
class variable_subarg : public subarg class subarg_variable_t : public subarg_t
{ {
public: public:
variable_subarg(variable* in=nullptr, bool inq=false) { type=_obj::subarg_variable; var=in; quoted=inq; } subarg_variable_t(variable_t* in=nullptr, bool inq=false) { type=_obj::subarg_variable; var=in; quoted=inq; }
~variable_subarg() { ~subarg_variable_t() {
if(var!=nullptr) delete var; if(var!=nullptr) delete var;
} }
variable* var; variable_t* var;
std::string generate(int ind) { return "$" + var->generate(ind); } std::string generate(int ind) { return "$" + var->generate(ind); }
}; };
class arithmetic_subarg : public subarg class subarg_arithmetic_t : public subarg_t
{ {
public: public:
arithmetic_subarg(arithmetic* a=nullptr) { type=_obj::subarg_arithmetic; arith=a; } subarg_arithmetic_t(arithmetic_t* a=nullptr) { type=_obj::subarg_arithmetic; arith=a; }
~arithmetic_subarg() { ~subarg_arithmetic_t() {
if(arith!=nullptr) delete arith; if(arith!=nullptr) delete arith;
} }
arithmetic* arith; arithmetic_t* arith;
std::string generate(int ind); std::string generate(int ind);
}; };
class subshell_subarg : public subarg class subarg_subshell_t : public subarg_t
{ {
public: public:
subshell_subarg(subshell* in=nullptr, bool inq=false) { type=_obj::subarg_subshell; sbsh=in; quoted=inq; } subarg_subshell_t(subshell_t* in=nullptr, bool inq=false, bool is_backtick=false) { type=_obj::subarg_subshell; sbsh=in; quoted=inq; backtick=is_backtick; }
~subshell_subarg() { if(sbsh != nullptr) delete sbsh; } ~subarg_subshell_t() { if(sbsh != nullptr) delete sbsh; }
subshell* sbsh; subshell_t* sbsh;
bool backtick;
std::string generate(int ind); std::string generate(int ind);
}; };
class procsub_subarg : public subarg class subarg_procsub_t : public subarg_t
{ {
public: public:
procsub_subarg() { type=_obj::subarg_procsub; sbsh=nullptr; is_output=false; } subarg_procsub_t() { type=_obj::subarg_procsub; sbsh=nullptr; is_output=false; }
procsub_subarg(bool output, subshell* in) { type=_obj::subarg_procsub; sbsh=in; is_output=output; } subarg_procsub_t(bool output, subshell_t* in) { type=_obj::subarg_procsub; sbsh=in; is_output=output; }
~procsub_subarg() { if(sbsh!=nullptr) delete sbsh; } ~subarg_procsub_t() { if(sbsh!=nullptr) delete sbsh; }
bool is_output; bool is_output;
subshell* sbsh; subshell_t* sbsh;
std::string generate(int ind); std::string generate(int ind);
}; };
// Arithmetic subtypes // // Arithmetic subtypes //
class operation_arithmetic : public arithmetic class arithmetic_operation_t : public arithmetic_t
{ {
public: public:
operation_arithmetic(std::string op="", arithmetic* a=nullptr, arithmetic* b=nullptr, bool pre=false) { type=_obj::arithmetic_operation; oper=op; val1=a; val2=b; precedence=pre; } arithmetic_operation_t(std::string op="", arithmetic_t* a=nullptr, arithmetic_t* b=nullptr, bool pre=false) { type=_obj::arithmetic_operation; oper=op; val1=a; val2=b; precedence=pre; }
~operation_arithmetic() { ~arithmetic_operation_t() {
if(val1 != nullptr) delete val1; if(val1 != nullptr) delete val1;
if(val2 != nullptr) delete val2; if(val2 != nullptr) delete val2;
} }
std::string oper; std::string oper;
bool precedence; bool precedence;
arithmetic *val1, *val2; arithmetic_t *val1, *val2;
std::string generate(int ind); std::string generate(int ind);
}; };
class subshell_arithmetic : public arithmetic class arithmetic_subshell_t : public arithmetic_t
{ {
public: public:
subshell_arithmetic(subshell* a=nullptr) { type=_obj::arithmetic_subshell; sbsh=a; } arithmetic_subshell_t(subshell_t* a=nullptr) { type=_obj::arithmetic_subshell; sbsh=a; }
~subshell_arithmetic() { ~arithmetic_subshell_t() {
if(sbsh!=nullptr) delete sbsh; if(sbsh!=nullptr) delete sbsh;
} }
subshell* sbsh; subshell_t* sbsh;
std::string generate(int ind); std::string generate(int ind);
}; };
class parenthesis_arithmetic : public arithmetic class arithmetic_parenthesis_t : public arithmetic_t
{ {
public: public:
parenthesis_arithmetic(arithmetic* a=nullptr) { type=_obj::arithmetic_parenthesis; val=a; } arithmetic_parenthesis_t(arithmetic_t* a=nullptr) { type=_obj::arithmetic_parenthesis; val=a; }
~parenthesis_arithmetic() { ~arithmetic_parenthesis_t() {
if(val!=nullptr) delete val; if(val!=nullptr) delete val;
} }
arithmetic* val; arithmetic_t* val;
std::string generate(int ind); std::string generate(int ind);
}; };
class number_arithmetic : public arithmetic class arithmetic_number_t : public arithmetic_t
{ {
public: public:
number_arithmetic(std::string const& a) { type=_obj::arithmetic_number; val=a; } arithmetic_number_t(std::string const& a) { type=_obj::arithmetic_number; val=a; }
std::string val; std::string val;
std::string generate(int ind) { return val; } std::string generate(int ind) { return val; }
}; };
class variable_arithmetic : public arithmetic class arithmetic_variable_t : public arithmetic_t
{ {
public: public:
variable_arithmetic(variable* in=nullptr) { type=_obj::arithmetic_variable; var=in; } arithmetic_variable_t(variable_t* in=nullptr) { type=_obj::arithmetic_variable; var=in; }
~variable_arithmetic() { ~arithmetic_variable_t() {
if(var!=nullptr) delete var; if(var!=nullptr) delete var;
} }
variable* var; variable_t* var;
std::string generate(int ind); std::string generate(int ind);
}; };

View file

@ -4,43 +4,43 @@
#include "struc.hpp" #include "struc.hpp"
// makers // makers
arg* make_arg(std::string const& in); arg_t* make_arg(std::string const& in);
cmd* make_cmd(std::vector<const char*> const& args); cmd_t* make_cmd(std::vector<const char*> const& args);
cmd* make_cmd(std::vector<std::string> const& args); cmd_t* make_cmd(std::vector<std::string> const& args);
cmd* make_cmd(std::vector<arg*> const& args); cmd_t* make_cmd(std::vector<arg_t*> const& args);
cmd* make_cmd(std::string const& in); cmd_t* make_cmd(std::string const& in);
pipeline* make_pipeline(std::vector<block*> const& bls); pipeline_t* make_pipeline(std::vector<block_t*> const& bls);
pipeline* make_pipeline(std::string const& in); pipeline_t* make_pipeline(std::string const& in);
condlist* make_condlist(std::string const& in); condlist_t* make_condlist(std::string const& in);
list* make_list(std::string const& in); list_t* make_list(std::string const& in);
block* make_block(std::string const& in); block_t* make_block(std::string const& in);
// copy // copy
arg* copy(arg* in); arg_t* copy(arg_t* in);
variable* copy(variable* in); variable_t* copy(variable_t* in);
// testers // testers
bool arg_has_char(char c, arg* in); bool arg_has_char(char c, arg_t* in);
bool possibly_expands(arg* in); bool possibly_expands(arg_t* in);
bool possibly_expands(arglist* in); bool possibly_expands(arglist_t* in);
// modifiers // modifiers
void force_quotes(arg* in); void force_quotes(arg_t* in);
void add_quotes(arg* in); void add_quotes(arg_t* in);
cmd* make_printf(arg* in); cmd_t* make_printf(arg_t* in);
inline cmd* make_printf_variable(std::string const& name) { inline cmd_t* make_printf_variable(std::string const& name) {
return make_printf(new arg(new variable_subarg(new variable(name)))); return make_printf(new arg_t(new subarg_variable_t(new variable_t(name))));
} }
arithmetic* make_arithmetic(arg* a); arithmetic_t* make_arithmetic(arg_t* a);
arithmetic* make_arithmetic(arg* arg1, std::string op, arg* arg2); arithmetic_t* make_arithmetic(arg_t* arg1, std::string op, arg_t* arg2);
// operators // operators
inline bool operator==(arg a, std::string const& b) { return a.equals(b); } inline bool operator==(arg_t a, std::string const& b) { return a.equals(b); }
#endif //STRUC_HELPER_HPP #endif //STRUC_HELPER_HPP

View file

@ -1,6 +1,6 @@
#ifndef VERSION_H #ifndef VERSION_H
#define VERSION_H #define VERSION_H
#define VERSION_STRING "v1.3.1" #define VERSION_STRING "v1.5"
#endif //VERSION_H #endif //VERSION_H

233
run-tests.sh Executable file
View file

@ -0,0 +1,233 @@
#!/bin/bash
bin=${1-./lxsh}
echo_red()
{
printf "\033[1;31m%s\033[0m\n" "$*"
exit 1
}
err=0
# $1 = file , $2 = extra print
# _LXSH_OPT : lxsh options
compile_test()
{
printf "%s%s: " "$1" "$2"
if errout=$($bin $_LXSH_OPT "$1" 2>&1 >/dev/null)
then
echo "Ok"
else
echo_red "Error"
echo "$errout"
return 1
fi
}
# $1 = runner , $2 = file , $3 = extra print , $4 = runtime for lxsh
# _LXSH_OPT : lxsh options
exec_test()
{
run=$1
lxshrun=${4-$run}
ret1=$($run "$2")
stat1=$?
ret2=$($bin $_LXSH_OPT "$2" | $lxshrun)
stat2=$?
printf "%s%s: " "$2" "$3"
if [ "$ret1" = "$ret2" ] && [ $stat1 -eq $stat2 ]
then echo "Ok"
else
echo_red "Error"
echo ">> original stat $stat1
$ret1
>> compiled stat $stat2
$ret2"
return 1
fi
}
size_test()
{
shebang=$(head -n1 "$1" | grep '^#!')
c1=$($bin --no-shebang -m "$1" | wc -c)
c2=$($bin -m "$1" | shfmt -mn | wc -c)
printf "%s%s: " "$1" "$2"
if [ $c1 -lt $c2 ]
then echo "Ok"
else
echo_red "Too big"
return 1
fi
}
# $1 = file , $2 = extra print , $3 = list , $@ = run options
list_test()
{
printf "%s%s: " "$1" "$2"
file=$1
varlist=$3
shift 3
diffout=$(diff <($bin "$file" "$@" | sort -k2) <(echo "$varlist" | sed '/^$/d' | sort -k2) )
if [ -z "$diffout" ] ; then
echo "Ok"
else
echo_red "Variable mismatch"
echo "$diffout"
return 1
fi
}
resolve="test/include.sh test/resolve.sh"
exec_exclude="test/prompt.sh $resolve"
echo "
============
| sh |
============
"
echo "== Parse =="
for I in test/*.sh
do
compile_test "$I" || err=$((err+1))
done
echo "== Exec =="
for I in $( echo test/*.sh $exec_exclude | tr -s ' \n' '\n' | sort | uniq -u )
do
exec_test sh "$I" || err=$((err+1))
_LXSH_OPT=-M exec_test sh "$I" " (minify)" || err=$((err+1))
done
echo "== Size =="
for I in test/*.sh
do
size_test "$I" || err=$((err+1))
done
echo "== Resolve =="
for I in $resolve
do
printf "%s: " "$I"
if errmsg=$($bin "$I" | sh 2>&1 >/dev/null) && [ -z "$errmsg" ]
then echo "Ok"
else
echo_red "Error"
echo ">> stderr
$errmsg"
err=$((err+1))
fi
done
varlist="
2 nul
2 ABCD
1 AYE
1 BAR
3 FOO
2 TATA
1 TITI
4 TOTO
1 TUTU
4 somevar
"
vardefs="
1 ABCD
1 BAR
2 FOO
1 TATA
1 TOTO
1 TUTU
1 nul
2 somevar
"
varcalls="
1 AYE
1 ABCD
1 FOO
1 TATA
1 TITI
3 TOTO
1 nul
2 somevar
"
varlist_used="
1 AYE
2 ABCD
3 FOO
2 TATA
1 TITI
4 TOTO
2 nul
4 somevar
"
echo "== Variables =="
{
list_test test/var.sh " (list)" "$varlist" --list-var || err=$((err+1))
list_test test/var.sh " (list-def)" "$vardefs" --list-var-def || err=$((err+1))
list_test test/var.sh " (list-call)" "$varcalls" --list-var-call || err=$((err+1))
list_test test/var.sh " (remove unused)" "$varlist_used" --remove-unused --list-var || err=$((err+1))
}
fctlist="
1 toto
1 tata
"
fctlist_used="
1 toto
"
cmdlist="
2 echo
1 toto
"
echo "== Functions =="
{
list_test test/fct.sh " (list-fct)" "$fctlist" --list-fct || err=$((err+1))
list_test test/fct.sh " (list-cmd)" "$cmdlist" --list-cmd || err=$((err+1))
list_test test/fct.sh " (remove unused)" "$fctlist_used" --remove-unused --list-fct || err=$((err+1))
}
echo "
============
| bash |
============
"
echo "== Parse =="
for I in test/*.bash
do
compile_test "$I" || err=$((err+1))
done
echo "== Exec =="
for I in test/*.bash
do
exec_test bash "$I" || err=$((err+1))
_LXSH_OPT=-m exec_test bash "$I" " (minify)" || err=$((err+1))
done
echo "== Size =="
for I in test/*.bash
do
size_test "$I" || err=$((err+1))
done
echo "== Debashify =="
for I in test/{debashify.bash,array.bash,echo.bash}
do
_LXSH_OPT=--debashify exec_test bash "$I" "" sh || err=$((err+1))
_LXSH_OPT="-m --debashify" exec_test bash "$I" " (minify)" sh || err=$((err+1))
done
exit $err

View file

@ -1,6 +1,6 @@
_lxsh_array_create() { _lxsh_array_create() {
printf "%s" "$1" printf "%s" "$1"
shift 1 shift 1 2>/dev/null || return
for N ; do for N ; do
printf "\t%s" "$N" printf "\t%s" "$N"
done done

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,9 @@
#define PIPE_READ 0 #define PIPE_READ 0
#define PIPE_WRITE 1 #define PIPE_WRITE 1
std::vector<condlist*> do_include_exec(condlist* cmd, parse_context ctx, FILE* fd) std::vector<condlist_t*> do_include_exec(condlist_t* cmd, parse_context ctx, FILE* fd)
{ {
std::vector<condlist*> ret; std::vector<condlist_t*> ret;
std::string dir; std::string dir;
auto incs=do_include_raw(cmd, ctx, &dir); auto incs=do_include_raw(cmd, ctx, &dir);
@ -36,9 +36,9 @@ std::vector<condlist*> do_include_exec(condlist* cmd, parse_context ctx, FILE* f
} }
// if first is nullptr: is a string // if first is nullptr: is a string
std::vector<condlist*> do_resolve_exec(condlist* cmd, parse_context ctx, FILE* fd) std::vector<condlist_t*> do_resolve_exec(condlist_t* cmd, parse_context ctx, FILE* fd)
{ {
std::vector<condlist*> ret; std::vector<condlist_t*> ret;
std::pair<std::string,std::string> p; std::pair<std::string,std::string> p;
try try
@ -61,9 +61,9 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, parse_context ctx, FILE* f
// -- OBJECT CALLS -- // -- OBJECT CALLS --
bool resolve_condlist_exec(condlist* in, parse_context ctx, FILE* fd) bool resolve_condlist_exec(condlist_t* in, parse_context ctx, FILE* fd)
{ {
cmd* tc = in->first_cmd(); cmd_t* tc = in->first_cmd();
if(tc == nullptr) if(tc == nullptr)
return false; return false;
@ -83,7 +83,7 @@ bool resolve_condlist_exec(condlist* in, parse_context ctx, FILE* fd)
} }
bool resolve_exec(condlist* in, parse_context ctx, FILE* fd) bool resolve_exec(condlist_t* in, parse_context ctx, FILE* fd)
{ {
if(!resolve_condlist_exec(in, ctx, fd)) if(!resolve_condlist_exec(in, ctx, fd))
{ {
@ -143,7 +143,7 @@ void parse_exec(FILE* fd, parse_context ctx)
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
debashify_params debash_params; debashify_params debash_params;
list* t_lst=new list; list_t* t_lst=new list_t;
if(t_lst == nullptr) if(t_lst == nullptr)
throw std::runtime_error("Alloc error"); throw std::runtime_error("Alloc error");
while(ctx.i<ctx.size) while(ctx.i<ctx.size)
@ -236,17 +236,18 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
if(mkfifo(fifopath.c_str(), 0700)<0) if(mkfifo(fifopath.c_str(), 0700)<0)
throw std::runtime_error("Cannot create fifo "+fifopath); throw std::runtime_error("Cannot create fifo "+fifopath);
for(uint32_t i=0; i<strargs.size(); i++)
runargs.push_back((char*) strargs[i].c_str());
runargs.push_back((char*) fifopath.c_str());
for(uint32_t i=0; i<args.size(); i++)
runargs.push_back((char*) args[i].c_str());
runargs.push_back(NULL);
pid_t pid=0; pid_t pid=0;
FILE* ffd=0; FILE* ffd=0;
try try
{ {
for(uint32_t i=0; i<strargs.size(); i++)
runargs.push_back((char*) strargs[i].c_str());
runargs.push_back((char*) fifopath.c_str());
for(uint32_t i=0; i<args.size(); i++)
runargs.push_back((char*) args[i].c_str());
runargs.push_back(NULL);
pid = forkexec(runargs[0], runargs.data()); pid = forkexec(runargs[0], runargs.data());
ffd = fopen(fifopath.c_str(), "w"); ffd = fopen(fifopath.c_str(), "w");
if(options["debashify"]) if(options["debashify"])
@ -260,10 +261,10 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
} }
catch(std::runtime_error& e) catch(std::runtime_error& e)
{ {
fclose(ffd);
unlink(fifopath.c_str());
if(pid != 0) if(pid != 0)
kill(pid, SIGINT); kill(pid, SIGINT);
fclose(ffd);
unlink(fifopath.c_str());
throw e; throw e;
} }

View file

@ -22,7 +22,7 @@ std::string indented(std::string const& in, uint32_t ind)
return in; return in;
} }
std::string arg::generate(int ind) std::string arg_t::generate(int ind)
{ {
std::string ret; std::string ret;
for(auto it: sa) for(auto it: sa)
@ -32,7 +32,7 @@ std::string arg::generate(int ind)
return ret; return ret;
} }
std::string arglist::generate(int ind) std::string arglist_t::generate(int ind)
{ {
std::string ret; std::string ret;
@ -47,7 +47,7 @@ std::string arglist::generate(int ind)
return ret; return ret;
} }
std::string pipeline::generate(int ind, generate_context* ctx) std::string pipeline_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -56,6 +56,10 @@ std::string pipeline::generate(int ind, generate_context* ctx)
if(negated) if(negated)
ret += "! "; ret += "! ";
if(bash_time)
ret += "time ";
ret += cmds[0]->generate(ind, ctx); ret += cmds[0]->generate(ind, ctx);
for(uint32_t i=1 ; i<cmds.size() ; i++) for(uint32_t i=1 ; i<cmds.size() ; i++)
{ {
@ -66,7 +70,7 @@ std::string pipeline::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string condlist::generate(int ind) std::string condlist_t::generate(int ind)
{ {
std::string ret; std::string ret;
if(pls.size() <= 0) if(pls.size() <= 0)
@ -90,6 +94,7 @@ std::string condlist::generate(int ind)
ret += '&'; ret += '&';
ret += '\n'; ret += '\n';
ret += ctx.here_document->generate(0); ret += ctx.here_document->generate(0);
ret += '\n';
prev_is_heredoc=true; prev_is_heredoc=true;
} }
else if(parallel) else if(parallel)
@ -101,7 +106,7 @@ std::string condlist::generate(int ind)
return ret; return ret;
} }
std::string list::generate(int ind, bool first_indent) std::string list_t::generate(int ind, bool first_indent)
{ {
std::string ret; std::string ret;
if(cls.size() <= 0) if(cls.size() <= 0)
@ -126,21 +131,22 @@ std::string list::generate(int ind, bool first_indent)
return ret; return ret;
} }
std::string redirect::generate(int ind) std::string redirect_t::generate(int ind)
{ {
std::string ret=op; std::string ret=op;
if(target!=nullptr) if(target!=nullptr)
{ {
if(!opt_minify) std::string targetret=target->generate(0);
if(!(opt_minify && !is_in(targetret[0], "<>")))
ret += ' '; ret += ' ';
ret += target->generate(0); ret += targetret;
} }
return ret; return ret;
} }
// BLOCK // BLOCK
std::string block::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr) std::string block_t::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr)
{ {
std::string ret=" "; std::string ret=" ";
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]); bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
@ -162,7 +168,7 @@ std::string block::generate_redirs(int ind, std::string const& _str, generate_co
return ret; return ret;
} }
std::string if_block::generate(int ind, generate_context* ctx) std::string if_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -196,7 +202,7 @@ std::string if_block::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string for_block::generate(int ind, generate_context* ctx) std::string for_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -217,7 +223,7 @@ std::string for_block::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string while_block::generate(int ind, generate_context* ctx) std::string while_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -237,7 +243,7 @@ std::string while_block::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string subshell::generate(int ind, generate_context* ctx) std::string subshell_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
// open subshell // open subshell
@ -270,7 +276,7 @@ std::string shmain::generate(bool print_shebang, int ind)
return ret; return ret;
} }
std::string brace::generate(int ind, generate_context* ctx) std::string brace_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -282,7 +288,7 @@ std::string brace::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string function::generate(int ind, generate_context* ctx) std::string function_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
// function definition // function definition
@ -297,7 +303,7 @@ std::string function::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string case_block::generate(int ind, generate_context* ctx) std::string case_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
ret += "case " + carg->generate(ind) + " in\n"; ret += "case " + carg->generate(ind) + " in\n";
@ -338,7 +344,7 @@ std::string case_block::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string cmd::generate(int ind, generate_context* ctx) std::string cmd_t::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -396,12 +402,19 @@ std::string cmd::generate(int ind, generate_context* ctx)
// SUBARG // SUBARG
std::string subshell_subarg::generate(int ind) std::string subarg_subshell_t::generate(int ind)
{ {
return '$' + sbsh->generate(ind); std::string r = sbsh->generate(ind);
if(backtick) {
r[0] = '`';
r[r.size()-1] = '`';
return r;
}
else
return '$' + r;
} }
std::string procsub_subarg::generate(int ind) std::string subarg_procsub_t::generate(int ind)
{ {
if(is_output) if(is_output)
return '>' + sbsh->generate(ind); return '>' + sbsh->generate(ind);
@ -409,7 +422,7 @@ std::string procsub_subarg::generate(int ind)
return '<' + sbsh->generate(ind); return '<' + sbsh->generate(ind);
} }
std::string arithmetic_subarg::generate(int ind) std::string subarg_arithmetic_t::generate(int ind)
{ {
std::string ret; std::string ret;
ret += "$(("; ret += "$((";
@ -422,7 +435,7 @@ std::string arithmetic_subarg::generate(int ind)
// ARITHMETIC // ARITHMETIC
std::string operation_arithmetic::generate(int ind) std::string arithmetic_operation_t::generate(int ind)
{ {
std::string ret; std::string ret;
if(precedence) if(precedence)
@ -442,7 +455,7 @@ std::string operation_arithmetic::generate(int ind)
return ret; return ret;
} }
std::string parenthesis_arithmetic::generate(int ind) std::string arithmetic_parenthesis_t::generate(int ind)
{ {
std::string ret; std::string ret;
ret += '('; ret += '(';
@ -453,12 +466,12 @@ std::string parenthesis_arithmetic::generate(int ind)
return ret; return ret;
} }
std::string subshell_arithmetic::generate(int ind) std::string arithmetic_subshell_t::generate(int ind)
{ {
return '$' + sbsh->generate(ind); return '$' + sbsh->generate(ind);
} }
std::string variable_arithmetic::generate(int ind) std::string arithmetic_variable_t::generate(int ind)
{ {
std::string ret=var->generate(ind); std::string ret=var->generate(ind);
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip) if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip)
@ -466,7 +479,7 @@ std::string variable_arithmetic::generate(int ind)
return ret; return ret;
} }
std::string variable::generate(int ind) std::string variable_t::generate(int ind)
{ {
std::string ret; std::string ret;
if(is_manip) if(is_manip)

View file

@ -72,7 +72,7 @@ int main(int argc, char* argv[])
// parsing // parsing
sh = new shmain(new list); sh = new shmain;
bool is_exec = false; bool is_exec = false;
bool first_run = true; bool first_run = true;
@ -94,7 +94,14 @@ int main(int argc, char* argv[])
{ {
first_run=false; first_run=false;
// resolve shebang // resolve shebang
if(options["bash"]) if(options["lxsh"])
{
shebang_is_bin = true;
parse_bash = true;
binshebang = basename(shebang);
shebang = "#!/usr/bin/env lxsh";
}
else if(options["bash"])
{ {
parse_bash=true; parse_bash=true;
shebang = "#!/usr/bin/env bash"; shebang = "#!/usr/bin/env bash";
@ -131,7 +138,6 @@ int main(int argc, char* argv[])
} }
// parse // parse
g_origin=file;
if(!add_include(file)) if(!add_include(file))
continue; continue;
@ -140,6 +146,8 @@ int main(int argc, char* argv[])
ctx = make_context(filecontents, file, parse_bash); ctx = make_context(filecontents, file, parse_bash);
if(is_exec) if(is_exec)
{ {
delete sh;
sh = nullptr;
args.erase(args.begin()); args.erase(args.begin());
return exec_process(shebang.substr(2), args, ctx); return exec_process(shebang.substr(2), args, ctx);
} }
@ -195,27 +203,38 @@ int main(int argc, char* argv[])
// processing before output // processing before output
// minify // minify
strmap_t varmap, fctmap;
if(options['m']) if(options['m'])
{ {
opt_minify=true; opt_minify=true;
minify_generic(sh); minify_generic(sh);
} }
if(options["minify-var"] && options["minify-fct"]) { if(options['A']) {
read_minmap(options['A'].argument, &varmap, &fctmap);
recurse(r_replace_var, sh, &varmap);
recurse(r_replace_fct, sh, &fctmap);
}
else if(options["minify-var"] && options["minify-fct"]) {
// optimization: get everything in one go // optimization: get everything in one go
allmaps_get(sh, re_var_exclude, re_fct_exclude, regex_null); allmaps_get(sh, re_var_exclude, re_fct_exclude, regex_null);
minify_var( sh, re_var_exclude ); varmap = minify_var( sh, re_var_exclude );
minify_fct( sh, re_fct_exclude ); fctmap = minify_fct( sh, re_fct_exclude );
} }
else if(options["minify-var"]) { else if(options["minify-var"]) {
minify_var( sh, re_var_exclude ); varmap = minify_var( sh, re_var_exclude );
} }
else if(options["minify-fct"]) { else if(options["minify-fct"]) {
minify_fct( sh, re_fct_exclude ); fctmap = minify_fct( sh, re_fct_exclude );
} }
// other processing // other processing
if(options["unset-var"]) if(options["unset-var"])
add_unset_variables( sh, re_var_exclude ); add_unset_variables( sh, re_var_exclude );
if(options['P']) {
std::ofstream(options['P'].argument) << gen_minmap(varmap, "var") << gen_minmap(fctmap, "fct");
}
#ifdef DEBUG_MODE #ifdef DEBUG_MODE
if(options['J']) if(options['J'])
{ {

View file

@ -1,14 +1,15 @@
#include "minify.hpp" #include "minify.hpp"
#include <fstream>
#include "parse.hpp" #include "parse.hpp"
#include "recursive.hpp" #include "recursive.hpp"
#include "processing.hpp" #include "processing.hpp"
#include "util.hpp" #include "util.hpp"
std::vector<subarg*> cmd::subarg_vars() std::vector<subarg_t*> cmd_t::subarg_vars()
{ {
std::vector<subarg*> ret; std::vector<subarg_t*> ret;
if(args==nullptr || args->size()<=0) if(args==nullptr || args->size()<=0)
return ret; return ret;
@ -16,7 +17,7 @@ std::vector<subarg*> cmd::subarg_vars()
{ {
for(uint32_t i=1; i<args->size(); i++) for(uint32_t i=1; i<args->size(); i++)
{ {
arg* ta = args->args[i]; arg_t* ta = args->args[i];
if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string) if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string)
continue; continue;
if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0))) if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0)))
@ -34,19 +35,19 @@ bool r_replace_fct(_obj* in, strmap_t* fctmap)
switch(in->type) switch(in->type)
{ {
case _obj::block_function: { case _obj::block_function: {
function* t = dynamic_cast<function*>(in); function_t* t = dynamic_cast<function_t*>(in);
auto el=fctmap->find(t->name); auto el=fctmap->find(t->name);
if(el!=fctmap->end()) if(el!=fctmap->end())
t->name = el->second; t->name = el->second;
}; break; }; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd_t* t = dynamic_cast<cmd_t*>(in);
std::string cmdname = t->arg_string(0); std::string cmdname = t->arg_string(0);
auto el=fctmap->find(cmdname); auto el=fctmap->find(cmdname);
if(el!=fctmap->end()) if(el!=fctmap->end())
{ {
delete t->args->args[0]; delete t->args->args[0];
t->args->args[0] = new arg(el->second); t->args->args[0] = new arg_t(el->second);
} }
}; break; }; break;
default: break; default: break;
@ -58,8 +59,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_variable: { case _obj::variable: {
variable* t = dynamic_cast<variable*>(in); variable_t* t = dynamic_cast<variable_t*>(in);
auto el=varmap->find(t->varname); auto el=varmap->find(t->varname);
if(el!=varmap->end()) if(el!=varmap->end())
t->varname = el->second; t->varname = el->second;
@ -69,8 +70,20 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
return true; return true;
} }
const char* singlequote_escape_char=" \\\t!\"()|&*?~><#"; const char* singlequote_escape_char=" \\\t!\"()|&*?~><#$";
const char* doublequote_escape_char=" \t'|&\\*()?~><#"; const char* doublequote_escape_char=" \t'|&\\*()?~><#$";
uint32_t count_escape_char(std::string& in, uint32_t i, bool doublequote, std::string** estr, uint32_t* ei) {
if( ( doublequote && is_in(in[i], doublequote_escape_char) ) ||
( !doublequote && is_in(in[i], singlequote_escape_char) ) ) {
*estr = &in;
*ei = i;
return 1;
}
else if(in[i] == '\n') // \n: can't remove quotes
return 2;
return 0;
}
uint32_t count_escape_chars(std::string const& in, bool doublequote) uint32_t count_escape_chars(std::string const& in, bool doublequote)
{ {
uint32_t r=0; uint32_t r=0;
@ -105,123 +118,203 @@ bool is_this_quote(char c, bool is_doublequote)
return c == '\''; return c == '\'';
} }
void do_one_minify_quotes(string_subarg* in, bool prev_is_var, bool start_quoted) bool is_varname(const char c) {
return is_alphanum(c) || c == '_';
}
void do_minify_quotes(arg_t* in)
{ {
std::string& val = in->val; auto t = in->sa.begin();
if(val.size() <= 1) // global loop
return; while(true)
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; uint32_t i=0;
while(i<val.size() && !( val[i] == '\'' || val[i] == '"') ) // one iteration loop
while(true)
{ {
if(val[i] == '\\') bool doublequote=false;
i++; bool prev_is_var=false;
i++; bool end_is_var=false;
} bool has_substitution=false;
if(i>=val.size()) // end before finding quote: exit std::string* strstart = nullptr;
return; uint32_t quotestart=0;
if(val[i] == '"') std::string* strend = nullptr;
doublequote=true; uint32_t quoteend=0;
std::string* escapestr = nullptr;
j=i; uint32_t escapepos=0;
i++; uint32_t ce=0;
// loop to find start of quote
if(doublequote) while(true)
{
while(i<val.size() && val[i] != '"')
{ {
if(val[i] == '\\') // reached end: quit
if(t == in->sa.end())
return;
while((*t)->type != _obj::subarg_string)
{
// previous is alphanum var: removing quote can change varname
if((*t)->type == _obj::subarg_variable) {
subarg_variable_t* vs = dynamic_cast<subarg_variable_t*>(*t);
if(vs->var != nullptr && !vs->var->is_manip && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_num(vs->var->varname[0]) ) )
prev_is_var = true;
}
else
prev_is_var = false;
t++;
// quit when reached end of arg
if(t == in->sa.end())
return;
i=0;
}
std::string& val = dynamic_cast<subarg_string_t*>(*t)->val;
// don't attempt if <= 2 chars
if(in->sa.size() == 1 && val.size() <= 2)
return;
while(i<val.size() && !( val[i] == '\'' || val[i] == '"') )
{
if(val[i] == '\\')
i++;
i++; i++;
}
// if found: break and go to next step
if(i<val.size()) {
if(val[i] == '"')
doublequote=true;
strstart=&val;
quotestart=i;
i++;
break;
}
else {
t++;
i=0;
}
} // end of quote start loop
// loop to end of quote
while(true)
{
// reached end: quit
if(t == in->sa.end())
return;
while((*t)->type != _obj::subarg_string)
{
// previous is alphanum var: removing quote can change varname
if((*t)->type == _obj::subarg_variable) {
subarg_variable_t* vs = dynamic_cast<subarg_variable_t*>(*t);
if(vs->var != nullptr && !vs->var->is_manip && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_num(vs->var->varname[0]) ) )
end_is_var = true;
}
else
end_is_var = false;
has_substitution=true;
t++;
// quit when reached end of arg
if(t == in->sa.end())
return;
i=0;
}
std::string& val = dynamic_cast<subarg_string_t*>(*t)->val;
if(doublequote)
{
while(i<val.size() && val[i] != '"')
{
if(val[i] == '\\') {
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
}
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
}
if(i>=val.size()) { // end before finding quote: continue looping
t++;
i=0;
continue;
}
}
else
{
while(i<val.size() && val[i] != '\'')
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
if(i>=val.size()) { // end before finding quote: continue looping
t++;
i=0;
continue;
}
}
strend=&val;
quoteend=i;
break;
} // end of quote end loop
// has a substitution that can expand: don't dequote
if(!in->forcequoted && has_substitution) {
i++; i++;
continue;
} }
if(i>=val.size()) // end before finding quote: exit // too many escapes: don't dequote
return; if(ce > 1) {
}
else
{
while(i<val.size() && val[i] != '\'')
i++; i++;
if(i>=val.size()) // end before finding quote: exit continue;
return; }
// removing quotes changes variable name: don't dequote
if( ( prev_is_var && quotestart == 0 && strstart->size()>1 && is_varname((*strstart)[1]) ) ||
( end_is_var && quoteend == 0 && strend->size()>1 && is_varname((*strend)[1])) ) {
i++;
continue;
}
// prev char is a $ would create variable names: don't dequote
if( quotestart >= 1 && (*strstart)[quotestart-1] == '$' && (!doublequote ||
( strstart->size()>2 && is_varname((*strstart)[quotestart+1])))
) {
i++;
continue;
}
// do dequote
strend->erase(quoteend, 1);
// needs one escape
if(ce == 1) {
escapestr->insert(escapepos, "\\");
}
strstart->erase(quotestart, 1);
} }
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], singlequote_escape_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, '\\');
}
} }
} }
void do_minify_dollar(subarg_string_t* in)
{
std::string& val = in->val;
for(uint32_t i=0; i<val.size(); i++) {
// skip singlequote strings
if(val[i] == '\'') {
i++;
while(val[i] != '\'')
i++;
}
// has \$
if(i+1<val.size() && val[i] == '\\' && val[i+1] == '$') {
// char after $ is a varname
if(i+2<val.size() && (is_varname(val[i+2]) || is_in(val[i+2], SPECIAL_VARS) || val[i+2] == '{') )
continue;
val.erase(i, 1);
}
}
}
bool r_minify_useless_quotes(_obj* in) bool r_minify_useless_quotes(_obj* in)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_arg: { case _obj::arg: {
arg* t = dynamic_cast<arg*>(in); arg_t* t = dynamic_cast<arg_t*>(in);
for(uint32_t i=0; i<t->sa.size(); i++) do_minify_quotes(t);
{
// iterate subargs
if(t->sa[i]->type == _obj::subarg_string)
{
// has to be a 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)
{
// previous subarg is a direct variable (removing a quote could change variable name)
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 minify
continue;
do_one_minify_quotes(ss, prev_is_var, i>0 && t->sa[i-1]->quoted);
}
//if()
}
}; break; }; break;
case _obj::_redirect: { case _obj::subarg_string: {
subarg_string_t* t = dynamic_cast<subarg_string_t*>(in);
do_minify_dollar(t);
}; break;
case _obj::redirect: {
// for redirects: don't minify quotes on here documents // for redirects: don't minify quotes on here documents
redirect* t = dynamic_cast<redirect*>(in); redirect_t* t = dynamic_cast<redirect_t*>(in);
if(t->here_document != nullptr) if(t->here_document != nullptr)
{ {
recurse(r_minify_useless_quotes, t->target); recurse(r_minify_useless_quotes, t->target);
@ -301,7 +394,7 @@ strmap_t gen_minimal_map(countmap_t const& vars, set_t const& excluded)
// calls // calls
void minify_var(_obj* in, std::regex const& exclude) strmap_t minify_var(_obj* in, std::regex const& exclude)
{ {
// countmap_t vars; // countmap_t vars;
set_t excluded; set_t excluded;
@ -316,9 +409,10 @@ void minify_var(_obj* in, std::regex const& exclude)
// perform replace // perform replace
recurse(r_replace_var, in, &varmap); recurse(r_replace_var, in, &varmap);
require_rescan_var(); require_rescan_var();
return varmap;
} }
void minify_fct(_obj* in, std::regex const& exclude) strmap_t minify_fct(_obj* in, std::regex const& exclude)
{ {
// countmap_t fcts, cmdmap; // countmap_t fcts, cmdmap;
set_t excluded, unsets; set_t excluded, unsets;
@ -339,6 +433,7 @@ void minify_fct(_obj* in, std::regex const& exclude)
recurse(r_replace_fct, in, &fctmap); recurse(r_replace_fct, in, &fctmap);
require_rescan_fct(); require_rescan_fct();
require_rescan_cmd(); require_rescan_cmd();
return fctmap;
} }
bool delete_unused_fct(_obj* in, std::regex const& exclude) bool delete_unused_fct(_obj* in, std::regex const& exclude)
@ -422,14 +517,14 @@ bool r_minify_empty_manip(_obj* in)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_arg: { case _obj::arg: {
arg* t = dynamic_cast<arg*>(in); arg_t* t = dynamic_cast<arg_t*>(in);
for(uint32_t i=0; i<t->sa.size(); i++) for(uint32_t i=0; i<t->sa.size(); i++)
{ {
if(t->sa[i]->type == _obj::subarg_variable) if(t->sa[i]->type == _obj::subarg_variable)
{ {
// has to be a variable // has to be a variable
variable_subarg* ss = dynamic_cast<variable_subarg*>(t->sa[i]); subarg_variable_t* ss = dynamic_cast<subarg_variable_t*>(t->sa[i]);
if(ss->var->is_manip) if(ss->var->is_manip)
{ {
// if is a manip: possibility to skip it // if is a manip: possibility to skip it
@ -438,7 +533,7 @@ bool r_minify_empty_manip(_obj* in)
if(i+1<t->sa.size() && t->sa[i+1]->type == _obj::subarg_string) if(i+1<t->sa.size() && t->sa[i+1]->type == _obj::subarg_string)
{ {
// if next subarg is a string: check its first char // if next subarg is a string: check its first char
string_subarg* ss = dynamic_cast<string_subarg*>(t->sa[i+1]); subarg_string_t* ss = dynamic_cast<subarg_string_t*>(t->sa[i+1]);
char c = ss->val[0]; char c = ss->val[0];
// if its first would extend the var name: skip // if its first would extend the var name: skip
if(is_alphanum(c) || c == '_') if(is_alphanum(c) || c == '_')
@ -456,28 +551,34 @@ bool r_minify_empty_manip(_obj* in)
return true; return true;
} }
block* do_one_minify_single_block(block* in) pipeline_t* do_one_minify_single_block(block_t* in)
{ {
block* ret=nullptr; pipeline_t* ret=nullptr;
list* l=nullptr; list_t* l=nullptr;
if(in->type == _obj::block_brace) if(in->type == _obj::block_brace)
l = dynamic_cast<brace*>(in)->lst; l = dynamic_cast<brace_t*>(in)->lst;
else if(in->type == _obj::block_subshell) else if(in->type == _obj::block_subshell)
l = dynamic_cast<subshell*>(in)->lst; l = dynamic_cast<subshell_t*>(in)->lst;
if(l == nullptr) if(l == nullptr)
return nullptr; return nullptr;
// not a single cmd/block: not applicable // not a single pipeline: not applicable
if(l->cls.size() != 1 || l->cls[0]->pls.size() != 1 || l->cls[0]->pls[0]->cmds.size() != 1) if(l->cls.size() != 1 || l->cls[0]->pls.size() != 1)
return nullptr; return nullptr;
ret = l->cls[0]->pls[0]->cmds[0]; ret = l->cls[0]->pls[0];
// if is a subshell and has some env set: don't remove it // if is a subshell and has some env set: don't remove it
if(in->type == _obj::block_subshell && has_env_set(ret)) if(in->type == _obj::block_subshell && has_env_set(ret))
return nullptr; return nullptr;
// has a non-stdout/stdin redirect: not applicable
for(auto it: in->redirs) {
if(!is_in(it->op[0], "<>") )
return nullptr;
}
return ret; return ret;
} }
@ -485,32 +586,47 @@ bool r_minify_single_block(_obj* in)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_pipeline: { case _obj::pipeline: {
bool has_operated=false; bool has_operated=false;
do do
{ {
// loop operating on current // loop operating on current
// (if has operated, current object has changed) // (if has operated, current object has changed)
has_operated=false; has_operated=false;
pipeline* t = dynamic_cast<pipeline*>(in); pipeline_t* t = dynamic_cast<pipeline_t*>(in);
for(uint32_t i=0; i<t->cmds.size(); i++) for(uint32_t i=0; i<t->cmds.size(); i++)
{ {
block* ret = do_one_minify_single_block(t->cmds[i]); pipeline_t* ret = do_one_minify_single_block(t->cmds[i]);
if(ret != nullptr) { if(ret != nullptr) {
// concatenate redirects // concatenate redirects
for(uint32_t j=0; j<t->cmds[i]->redirs.size(); j++) block_t* firstb = ret->cmds[0];
ret->redirs.insert(ret->redirs.begin()+j, t->cmds[i]->redirs[j]); block_t* lastb = ret->cmds[ret->cmds.size()-1];
uint32_t j1=0, j2=0;
for(uint32_t j=0; j<t->cmds[i]->redirs.size(); j++) {
if(t->cmds[i]->redirs[j]->op[0] == '<') {
firstb->redirs.insert(firstb->redirs.begin()+j1, t->cmds[i]->redirs[j]);
j1++;
}
else {
lastb->redirs.insert(lastb->redirs.begin()+j2, t->cmds[i]->redirs[j]);
j2++;
}
}
// deindex // deindex
t->cmds[i]->redirs.resize(0); t->cmds[i]->redirs.resize(0);
if(t->cmds[i]->type == _obj::block_brace) if(t->cmds[i]->type == _obj::block_brace)
dynamic_cast<brace*>(t->cmds[i])->lst->cls[0]->pls[0]->cmds[0] = nullptr; dynamic_cast<brace_t*>(t->cmds[i])->lst->cls[0]->pls[0] = nullptr;
else if(t->cmds[i]->type == _obj::block_subshell) else if(t->cmds[i]->type == _obj::block_subshell)
dynamic_cast<subshell*>(t->cmds[i])->lst->cls[0]->pls[0]->cmds[0] = nullptr; dynamic_cast<subshell_t*>(t->cmds[i])->lst->cls[0]->pls[0] = nullptr;
// replace value // replace value
delete t->cmds[i]; delete t->cmds[i];
t->cmds[i] = ret; t->cmds.erase(t->cmds.begin()+i);
for(auto it: ret->cmds) {
t->cmds.insert(t->cmds.begin()+i, it);
i++;
}
has_operated=true; has_operated=true;
} }
@ -523,11 +639,54 @@ bool r_minify_single_block(_obj* in)
return true; return true;
} }
bool r_has_backtick(_obj* in, bool* r)
{
if(*r)
return false;
switch(in->type)
{
case _obj::subarg_subshell: {
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(in);
if(t->backtick) {
*r = true;
return false;
}
}; break;
case _obj::subarg_string: {
subarg_string_t* t = dynamic_cast<subarg_string_t*>(in);
if(t->val.find('\\') != std::string::npos)
*r = true;
}; break;
default: break;
}
return true;
}
bool r_minify_backtick(_obj* in)
{
switch(in->type)
{
case _obj::subarg_subshell: {
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(in);
if(!t->backtick) {
bool has_backtick_child=false;
recurse(r_has_backtick, t->sbsh, &has_backtick_child);
if(has_backtick_child)
return false;
t->backtick = true;
}
return false;
}; break;
default: break;
}
return true;
}
// optimisation for processors that don't have recurse-cancellation
bool r_minify(_obj* in) bool r_minify(_obj* in)
{ {
r_minify_empty_manip(in); r_minify_empty_manip(in);
r_minify_single_block(in); r_minify_single_block(in);
r_minify_useless_quotes(in);
r_do_string_processor(in); r_do_string_processor(in);
return true; return true;
} }
@ -535,4 +694,34 @@ bool r_minify(_obj* in)
void minify_generic(_obj* in) void minify_generic(_obj* in)
{ {
recurse(r_minify, in); recurse(r_minify, in);
recurse(r_minify_backtick, in);
recurse(r_minify_useless_quotes, in);
}
std::string gen_minmap(strmap_t const& map, std::string const& prefix)
{
std::string ret;
for(auto it: map) {
ret += strf("%s %s %s\n", prefix.c_str(), it.second.c_str(), it.first.c_str());
}
return ret;
}
void read_minmap(std::string const& filepath, strmap_t* varmap, strmap_t* fctmap)
{
std::ifstream file(filepath);
std::string ln;
while(std::getline(file, ln)) {
size_t s1, s2, s3;
s1 = ln.find(' ');
s2 = ln.find(' ', s1+1);
s3 = ln.find(' ', s2+1);
std::string type = ln.substr(0, s1);
std::string from = ln.substr(s1+1, s2-s1-1);
std::string to = ln.substr(s2+1, s3-s2-1);
if(type == "var")
varmap->insert(std::make_pair(from, to));
else if(type == "fct")
fctmap->insert(std::make_pair(from, to));
}
} }

View file

@ -20,6 +20,7 @@ ztd::option_set options( {
ztd::option('c', "stdout", false, "Output result script to stdout"), ztd::option('c', "stdout", false, "Output result script to stdout"),
ztd::option('e', "exec", false, "Directly execute script"), ztd::option('e', "exec", false, "Directly execute script"),
ztd::option("no-shebang", false, "Don't output shebang"), ztd::option("no-shebang", false, "Don't output shebang"),
ztd::option('P', "map", true , "Output var and fct minify map to given file", "file"),
#ifdef DEBUG_MODE #ifdef DEBUG_MODE
ztd::option("\r [Debugging]"), ztd::option("\r [Debugging]"),
ztd::option('J', "json", false, "Output the json structure"), ztd::option('J', "json", false, "Output the json structure"),
@ -27,11 +28,13 @@ ztd::option_set options( {
ztd::option("\r [Processing]"), ztd::option("\r [Processing]"),
ztd::option('m', "minify", false, "Minify code without changing functionality"), ztd::option('m', "minify", false, "Minify code without changing functionality"),
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-var --minify-fct --remove-unused"), ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-var --minify-fct --remove-unused"),
ztd::option('A', "apply-map", true , "Apply var/fct minify map from given file", "file"),
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"), ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
ztd::option('I', "no-include", false, "Don't resolve %include commands"), ztd::option('I', "no-include", false, "Don't resolve %include commands"),
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"), ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
ztd::option("no-extend", false, "Don't add lxsh extension functions"), ztd::option("no-extend", false, "Don't add lxsh extension functions"),
ztd::option("bash", false, "Force bash parsing"), ztd::option("bash", false, "Force bash parsing"),
ztd::option("lxsh", false, "Force lxsh parsing"),
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"), ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
ztd::option("remove-unused", false, "Remove unused functions and variables"), ztd::option("remove-unused", false, "Remove unused functions and variables"),
ztd::option("list-cmd", false, "List all commands invoked in the script"), ztd::option("list-cmd", false, "List all commands invoked in the script"),
@ -73,26 +76,34 @@ void get_opts()
options["minify-fct"].activated=true; options["minify-fct"].activated=true;
options["remove-unused"].activated=true; options["remove-unused"].activated=true;
} }
if(options['o'].argument == "-")
options['o'].argument = "/dev/stdout";
if(options['P'].argument == "-")
options['P'].argument = "/dev/stdout";
if(options['A'].argument == "-")
options['A'].argument = "/dev/stdin";
if(
options['A'] && ( options['P'] || options["minify-var"] || options["minify-fct"] )
) {
printf("Incompatible options\n");
exit(ERR_OPT);
}
} }
ztd::option_set create_include_opts() ztd::option_set create_include_opts()
{ {
ztd::option_set opts; return std::vector<ztd::option>({
opts.add(
ztd::option('C', false, "Don't cd to folder the file is in"), ztd::option('C', false, "Don't cd to folder the file is in"),
ztd::option('f', false, "Force include even if already included. Don't count as included") ztd::option('f', false, "Force include even if already included. Don't count as included")
); });
return opts;
} }
ztd::option_set create_resolve_opts() ztd::option_set create_resolve_opts()
{ {
ztd::option_set opts; return std::vector<ztd::option>({
opts.add(
ztd::option('C', false, "Don't cd to folder this file is in"), ztd::option('C', false, "Don't cd to folder this file is in"),
ztd::option('f', false, "Ignore non-zero return values") ztd::option('f', false, "Ignore non-zero return values")
); });
return opts;
} }
void print_help(const char* arg0) void print_help(const char* arg0)
@ -125,7 +136,7 @@ void print_resolve_help()
printf("Execute shell command and substitute output, from folder of current file\n"); printf("Execute shell command and substitute output, from folder of current file\n");
printf(" - Default behaviour is to parse contents as shell code\n"); printf(" - Default behaviour is to parse contents as shell code\n");
printf(" - Fails if return value is not 0. Can be ignored with -f\n"); printf(" - Fails if return value is not 0. Can be ignored with -f\n");
printf(" - `%%include` inside substitutions replaces the substitution and puts raw response\n"); printf(" - `%%resolve` inside substitutions replaces the substitution and puts raw response\n");
printf("\n"); printf("\n");
ztd::option_set opts=create_resolve_opts(); ztd::option_set opts=create_resolve_opts();

View file

@ -18,7 +18,7 @@ const std::set<std::string> posix_cmdvar = { "export", "unset", "local", "read",
const std::set<std::string> bash_cmdvar = { "readonly", "declare", "typeset" }; const std::set<std::string> bash_cmdvar = { "readonly", "declare", "typeset" };
const std::set<std::string> arithmetic_precedence_operators = { "!", "~", "+", "-" }; const std::set<std::string> arithmetic_precedence_operators = { "!", "~", "+", "-" };
const std::set<std::string> arithmetic_operators = { "+", "-", "*", "/", "+=", "-=", "*=", "/=", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" }; const std::set<std::string> arithmetic_operators = { "+", "-", "*", "/", "%", "+=", "-=", "*=", "/=", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" };
const std::set<std::string> all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" }; const std::set<std::string> all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" };
const std::set<std::string> out_reserved_words = { "then", "else", "fi", "esac", "do", "done", "}" }; const std::set<std::string> out_reserved_words = { "then", "else", "fi", "esac", "do", "done", "}" };
@ -103,11 +103,9 @@ parse_context make_context(std::string const& in, std::string const& filename, b
parse_context make_context(parse_context ctx, std::string const& in, std::string const& filename, bool bash) parse_context make_context(parse_context ctx, std::string const& in, std::string const& filename, bool bash)
{ {
if(in != "") ctx.data = in.c_str();
{ ctx.size = in.size();
ctx.data = in.c_str();
ctx.size = in.size();
}
if(filename != "") if(filename != "")
ctx.filename = filename.c_str(); ctx.filename = filename.c_str();
if(bash) if(bash)
@ -207,9 +205,9 @@ std::pair<std::string,uint32_t> get_word(parse_context ctx, const char* end_set)
// parse fcts // parse fcts
std::pair<variable*, parse_context> parse_var(parse_context ctx, bool specialvars, bool array) std::pair<variable_t*, parse_context> parse_var(parse_context ctx, bool specialvars, bool array)
{ {
variable* ret=nullptr; variable_t* ret=nullptr;
std::string varname; std::string varname;
uint32_t start=ctx.i; uint32_t start=ctx.i;
@ -227,7 +225,7 @@ std::pair<variable*, parse_context> parse_var(parse_context ctx, bool specialvar
} }
if(varname != "") if(varname != "")
{ {
ret = new variable(varname); ret = new variable_t(varname);
if(ctx.bash && array && ctx[ctx.i]=='[') if(ctx.bash && array && ctx[ctx.i]=='[')
{ {
ctx.i++; ctx.i++;
@ -264,9 +262,9 @@ std::pair<std::string, uint32_t> get_operator(parse_context ctx)
// parse an arithmetic // parse an arithmetic
// ends at )) // ends at ))
// temporary, to improve // temporary, to improve
std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx) std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
{ {
arithmetic* ret = nullptr; arithmetic_t* ret = nullptr;
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
if(ctx.i>ctx.size || ctx[ctx.i] == ')') if(ctx.i>ctx.size || ctx[ctx.i] == ')')
@ -280,12 +278,12 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
{ {
ctx.i = po.second; ctx.i = po.second;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
ret = new operation_arithmetic(po.first, pa.first, nullptr, true); ret = new arithmetic_operation_t(po.first, pa.first, nullptr, true);
ctx=pa.second; ctx=pa.second;
} }
else else
{ {
variable_arithmetic* ttvar=nullptr; // for categorizing definitions arithmetic_variable_t* ttvar=nullptr; // for categorizing definitions
if(ctx[ctx.i]=='-' || is_num(ctx[ctx.i])) if(ctx[ctx.i]=='-' || is_num(ctx[ctx.i]))
{ {
uint32_t j=ctx.i; uint32_t j=ctx.i;
@ -293,27 +291,40 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++; ctx.i++;
while(is_num(ctx[ctx.i])) while(is_num(ctx[ctx.i]))
ctx.i++; ctx.i++;
ret = new number_arithmetic( std::string(ctx.data+j, ctx.i-j) ); ret = new arithmetic_number_t( std::string(ctx.data+j, ctx.i-j) );
}
else if(word_eq("$((", ctx)) // arithmetics in arithmetics: equivalent to ()
{
ctx.i += 3;
auto pa = parse_arithmetic(ctx);
ret = new arithmetic_parenthesis_t(pa.first);
ctx = pa.second;
ctx.i++;
if(ctx.i >= ctx.size || ctx[ctx.i] != ')') {
parse_error( "Unexpected ')', Expecting '))'", ctx );
return std::make_pair(ret, ctx);
}
ctx.i++;
} }
else if(word_eq("$(", ctx)) else if(word_eq("$(", ctx))
{ {
ctx.i+=2; ctx.i+=2;
auto ps = parse_subshell(ctx); auto ps = parse_subshell(ctx);
ret = new subshell_arithmetic(ps.first); ret = new arithmetic_subshell_t(ps.first);
ctx=ps.second; ctx=ps.second;
} }
else if(word_eq("${", ctx)) else if(word_eq("${", ctx))
{ {
ctx.i+=2; ctx.i+=2;
auto pm = parse_manipulation(ctx); auto pm = parse_manipulation(ctx);
ret = new variable_arithmetic(pm.first); ret = new arithmetic_variable_t(pm.first);
ctx=pm.second; ctx=pm.second;
} }
else if(ctx[ctx.i] == '(') else if(ctx[ctx.i] == '(')
{ {
ctx.i++; ctx.i++;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
ret = pa.first; ret = new arithmetic_parenthesis_t(pa.first);
ctx = pa.second; ctx = pa.second;
ctx.i++; ctx.i++;
} }
@ -326,7 +337,7 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++; ctx.i++;
} }
auto pp = parse_var(ctx, specialvars, true); auto pp = parse_var(ctx, specialvars, true);
ttvar = new variable_arithmetic(pp.first); ttvar = new arithmetic_variable_t(pp.first);
ret = ttvar; ret = ttvar;
ctx=pp.second; ctx=pp.second;
} }
@ -339,12 +350,12 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
{ {
parse_error( "Unknown arithmetic operator: "+po.first, ctx); parse_error( "Unknown arithmetic operator: "+po.first, ctx);
} }
arithmetic* val1 = ret; arithmetic_t* val1 = ret;
ctx.i=po.second; ctx.i=po.second;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
arithmetic* val2 = pa.first; arithmetic_t* val2 = pa.first;
ctx = pa.second; ctx = pa.second;
ret = new operation_arithmetic(po.first, val1, val2); ret = new arithmetic_operation_t(po.first, val1, val2);
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
} }
@ -366,10 +377,10 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<variable*, parse_context> parse_manipulation(parse_context ctx) std::pair<variable_t*, parse_context> parse_manipulation(parse_context ctx)
{ {
variable* ret = nullptr; variable_t* ret = nullptr;
arg* precede = nullptr; arg_t* precede = nullptr;
uint32_t start=ctx.i; uint32_t start=ctx.i;
@ -382,7 +393,7 @@ std::pair<variable*, parse_context> parse_manipulation(parse_context ctx)
} }
std::string t; std::string t;
t+=ctx[ctx.i]; t+=ctx[ctx.i];
precede = new arg( t ); precede = new arg_t( t );
ctx.i++; ctx.i++;
} }
@ -418,8 +429,10 @@ std::pair<variable*, parse_context> parse_manipulation(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j, bool is_quoted) inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t& j, bool is_quoted)
{ {
if( ctx.i >= ctx.size)
return ctx;
if( ctx[ctx.i] == '`' ) if( ctx[ctx.i] == '`' )
{ {
// add previous subarg // add previous subarg
@ -440,10 +453,12 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
} }
// get subshell // get subshell
parse_context newct = ctx; parse_context newct = ctx;
ctx.size=k; newct.size=k;
auto r=parse_list_until(newct); auto r=parse_list_until(newct);
ret->add(new subshell_subarg(new subshell(std::get<0>(r)), is_quoted)); ret->add(new subarg_subshell_t(new subshell_t(std::get<0>(r)), is_quoted, true));
uint64_t tsize=ctx.size;
ctx = std::get<1>(r); ctx = std::get<1>(r);
ctx.size = tsize;
ctx.i++; ctx.i++;
j = ctx.i; j = ctx.i;
} }
@ -455,7 +470,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
// get arithmetic // get arithmetic
ctx.i+=3; ctx.i+=3;
auto r=parse_arithmetic(ctx); auto r=parse_arithmetic(ctx);
arithmetic_subarg* tt = new arithmetic_subarg(r.first); subarg_arithmetic_t* tt = new subarg_arithmetic_t(r.first);
tt->quoted=is_quoted; tt->quoted=is_quoted;
ret->add(tt); ret->add(tt);
ctx = r.second; ctx = r.second;
@ -477,7 +492,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
// get subshell // get subshell
ctx.i+=2; ctx.i+=2;
auto r=parse_subshell(ctx); auto r=parse_subshell(ctx);
ret->add(new subshell_subarg(r.first, is_quoted)); ret->add(new subarg_subshell_t(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
@ -489,7 +504,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
// get manipulation // get manipulation
ctx.i+=2; ctx.i+=2;
auto r=parse_manipulation(ctx); auto r=parse_manipulation(ctx);
ret->add(new variable_subarg(r.first, is_quoted)); ret->add(new subarg_variable_t(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
@ -504,7 +519,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
if(ctx.i-j>0) if(ctx.i-j>0)
ret->add(std::string(ctx.data+j, ctx.i-j)); ret->add(std::string(ctx.data+j, ctx.i-j));
// add var // add var
ret->add(new variable_subarg(r.first, is_quoted)); ret->add(new subarg_variable_t(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
@ -539,9 +554,9 @@ bool _optimize_skip_arg(parse_context& ctx, const char* str) {
// parse one argument // parse one argument
// must start at a read char // must start at a read char
// ends at either " \t|&;\n()" // ends at either " \t|&;\n()"
std::pair<arg*, parse_context> parse_arg(parse_context ctx, const char* end, const char* unexpected, bool doquote, const char* optimize) std::pair<arg_t*, parse_context> parse_arg(parse_context ctx, const char* end, const char* unexpected, bool doquote, const char* optimize)
{ {
arg* ret = new arg; arg_t* ret = new arg_t;
// j : start of subarg , q = start of quote // j : start of subarg , q = start of quote
uint32_t j=ctx.i,q=ctx.i; uint32_t j=ctx.i,q=ctx.i;
@ -634,7 +649,6 @@ parse_context parse_heredocument(parse_context ctx)
{ {
ctx.i = ctx.size; ctx.i = ctx.size;
} }
// std::string tmpparse=std::string(ctx.data+j, ctx.i-j);
parse_context newctx = make_context(ctx, j); parse_context newctx = make_context(ctx, j);
newctx.size = ctx.i; newctx.size = ctx.i;
auto pval = parse_arg(newctx , NULL, NULL, false, ARG_OPTIMIZE_NULL); auto pval = parse_arg(newctx , NULL, NULL, false, ARG_OPTIMIZE_NULL);
@ -650,7 +664,19 @@ parse_context parse_heredocument(parse_context ctx)
return ctx; return ctx;
} }
std::pair<redirect*, parse_context> parse_redirect(parse_context ctx) std::pair<arg_t*, parse_context> parse_bash_procsub(parse_context ctx)
{
if(!ctx.bash)
{
parse_error(strf("bash specific: %c()", ctx[ctx.i]), ctx);
}
bool is_output = ctx[ctx.i] == '>';
ctx.i+=2;
auto ps = parse_subshell(ctx);
return std::make_pair(new arg_t(new subarg_procsub_t(is_output, ps.first)), ps.second);
}
std::pair<redirect_t*, parse_context> parse_redirect(parse_context ctx)
{ {
bool is_redirect=false; bool is_redirect=false;
bool needs_arg=false; bool needs_arg=false;
@ -737,9 +763,9 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
if(is_redirect) if(is_redirect)
{ {
redirect* ret=nullptr; redirect_t* ret=nullptr;
ret = new redirect; ret = new redirect_t;
ret->op = std::string(ctx.data+start, ctx.i-start); ret->op = std::string(ctx.data+start, ctx.i-start);
if(needs_arg) if(needs_arg)
{ {
@ -775,8 +801,12 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
} }
else else
{ {
auto pa = parse_arg(ctx); std::pair<arg_t*, parse_context> pa;
ret->target = pa.first; if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <()
pa = parse_bash_procsub(ctx);
else
pa = parse_arg(ctx);
ret->target=pa.first;
ctx=pa.second; ctx=pa.second;
} }
} }
@ -793,9 +823,9 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
// must start at a read char // must start at a read char
// first char has to be read // first char has to be read
// ends at either &|;\n#() // ends at either &|;\n#()
std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_error, std::vector<redirect*>* redirs) std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_error, std::vector<redirect_t*>* redirs, bool stop_on_brace)
{ {
arglist* ret = nullptr; arglist_t* ret = nullptr;
if(word_eq("[[", ctx, ARG_END) ) // [[ bash specific parsing if(word_eq("[[", ctx, ARG_END) ) // [[ bash specific parsing
{ {
@ -806,14 +836,14 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
while(true) while(true)
{ {
if(ret == nullptr) if(ret == nullptr)
ret = new arglist; ret = new arglist_t;
auto pp=parse_arg(ctx, SEPARATORS, NULL, true, ARG_OPTIMIZE_BASHTEST); auto pp=parse_arg(ctx, SEPARATORS, NULL, true, ARG_OPTIMIZE_BASHTEST);
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
if(word_eq("]]", ctx, ARG_END)) if(word_eq("]]", ctx, ARG_END))
{ {
ret->add(new arg("]]")); ret->add(new arg_t("]]"));
ctx.i+=2; ctx.i+=2;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
if( !is_in(ctx[ctx.i], ARGLIST_END) ) if( !is_in(ctx[ctx.i], ARGLIST_END) )
@ -846,17 +876,11 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
{ {
if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <() if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <()
{ {
if(!ctx.bash) auto pa=parse_bash_procsub(ctx);
{
parse_error(strf("bash specific: %c()", ctx[ctx.i]), ctx);
}
bool is_output = ctx[ctx.i] == '>';
ctx.i+=2;
if(ret == nullptr) if(ret == nullptr)
ret = new arglist; ret = new arglist_t;
auto ps = parse_subshell(ctx); ret->add(pa.first);
ret->add(new arg(new procsub_subarg(is_output, ps.first))); ctx=pa.second;
ctx=ps.second;
} }
else if(redirs!=nullptr) else if(redirs!=nullptr)
{ {
@ -871,10 +895,12 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
} }
else else
{ {
argparse: argparse: ;
if(ret == nullptr)
ret = new arglist;
auto pp=parse_arg(ctx); auto pp=parse_arg(ctx);
if(stop_on_brace && pp.first!=nullptr && pp.first->string() == "}")
return std::make_pair(ret, ctx);
if(ret == nullptr)
ret = new arglist_t;
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
} }
@ -901,23 +927,33 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
// must start at a read char // must start at a read char
// separated by | // separated by |
// ends at either &;\n#) // ends at either &;\n#)
std::pair<pipeline*, parse_context> parse_pipeline(parse_context ctx) std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ctx)
{ {
pipeline* ret = new pipeline; pipeline_t* ret = new pipeline_t;
if(ctx[ctx.i] == '!' && ctx.i+1<ctx.size && is_in(ctx[ctx.i+1], SPACES)) while(true) {
{ auto wp = get_word(ctx, ARG_END);
ret->negated = true; if(ctx[ctx.i] == '!' && ctx.i+1<ctx.size && is_in(ctx[ctx.i+1], SPACES))
ctx.i++; {
ctx.i=skip_chars(ctx, SPACES); ret->negated = ret->negated ? false : true;
ctx.i++;
ctx.i=skip_chars(ctx, SPACES);
} else if(ctx.bash && wp.first == "time" ) {
ret->bash_time = true;
ctx.i+=4;
ctx.i=skip_chars(ctx, SPACES);
} else {
break;
}
} }
while(ctx.i<ctx.size) while(ctx.i<ctx.size)
{ {
auto pp=parse_block(ctx); auto pp=parse_block(ctx);
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
if( ctx.i>=ctx.size || is_in(ctx[ctx.i], PIPELINE_END) || word_eq("||", ctx) ) if( ctx.i>=ctx.size || is_in(ctx[ctx.i], PIPELINE_END) || word_eq("||", ctx) || ctx[ctx.i] == '}' )
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
else if( ctx[ctx.i] != '|' ) else if( ctx[ctx.i] != '|' )
{ {
@ -941,9 +977,9 @@ std::pair<pipeline*, parse_context> parse_pipeline(parse_context ctx)
// must start at a read char // must start at a read char
// separated by && or || // separated by && or ||
// ends at either ;\n)# // ends at either ;\n)#
std::pair<condlist*, parse_context> parse_condlist(parse_context ctx) std::pair<condlist_t*, parse_context> parse_condlist(parse_context ctx)
{ {
condlist* ret = new condlist; condlist_t* ret = new condlist_t;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
bool optype=AND_OP; bool optype=AND_OP;
@ -952,7 +988,7 @@ std::pair<condlist*, parse_context> parse_condlist(parse_context ctx)
auto pp=parse_pipeline(ctx); auto pp=parse_pipeline(ctx);
ret->add(pp.first, optype); ret->add(pp.first, optype);
ctx = pp.second; ctx = pp.second;
if(ctx.i>=ctx.size || is_in(ctx[ctx.i], CONTROL_END) || is_in(ctx[ctx.i], COMMAND_SEPARATOR)) // end here exactly: used for control later if(ctx.i>=ctx.size || is_in(ctx[ctx.i], CONTROL_END) || is_in(ctx[ctx.i], COMMAND_SEPARATOR) || ctx[ctx.i] == '}') // end here exactly: used for control later
{ {
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
@ -994,9 +1030,9 @@ std::pair<condlist*, parse_context> parse_condlist(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx, list_parse_options opts) std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ctx, list_parse_options opts)
{ {
list* ret = new list; list_t* ret = new list_t;
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
std::string found_end_word; std::string found_end_word;
@ -1069,27 +1105,35 @@ std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx
if(ctx.here_document != nullptr) if(ctx.here_document != nullptr)
{ {
uint8_t do_twice=2; bool has_parsed=false;
// case of : cat << EOF ; parse_context t_ctx=ctx;
while(do_twice>0) if(t_ctx[t_ctx.i] == '\n')
{ {
if(ctx[ctx.i] == '\n') t_ctx = parse_heredocument(t_ctx+1);
{ has_parsed=true;
ctx = parse_heredocument(ctx+1);
break;
}
else if(ctx[ctx.i] == '#')
{
ctx.i = skip_until(ctx, "\n"); //skip to endline
ctx = parse_heredocument(ctx+1);
break;
}
skip_chars(ctx, SPACES);
do_twice--;
} }
// case of : cat << EOF ; ; else if(t_ctx[t_ctx.i] == '#')
if(do_twice==0 && is_in(ctx[ctx.i], COMMAND_SEPARATOR)) {
parse_error( unexpected_token(ctx[ctx.i]), ctx); t_ctx.i = skip_until(t_ctx, "\n"); //skip to endline
t_ctx = parse_heredocument(t_ctx+1);
has_parsed=true;
}
else if(t_ctx[t_ctx.i] == ';') {
t_ctx.i = skip_chars(t_ctx+1, SPACES);
if(t_ctx[t_ctx.i] == '\n')
{
t_ctx = parse_heredocument(t_ctx+1);
has_parsed=true;
}
else if(t_ctx[t_ctx.i] == '#')
{
t_ctx.i = skip_until(t_ctx, "\n"); //skip to endline
t_ctx = parse_heredocument(t_ctx+1);
has_parsed=true;
}
}
if(has_parsed)
ctx = t_ctx;
} }
if(is_in(ctx[ctx.i], COMMAND_SEPARATOR)) if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
@ -1116,9 +1160,9 @@ std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx
// parse a subshell // parse a subshell
// must start right after the opening ( // must start right after the opening (
// ends at ) and nothing else // ends at ) and nothing else
std::pair<subshell*, parse_context> parse_subshell(parse_context ctx) std::pair<subshell_t*, parse_context> parse_subshell(parse_context ctx)
{ {
subshell* ret = new subshell; subshell_t* ret = new subshell_t;
uint32_t start=ctx.i; uint32_t start=ctx.i;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
@ -1138,9 +1182,9 @@ std::pair<subshell*, parse_context> parse_subshell(parse_context ctx)
// parse a brace block // parse a brace block
// must start right after the opening { // must start right after the opening {
// ends at } and nothing else // ends at } and nothing else
std::pair<brace*, parse_context> parse_brace(parse_context ctx) std::pair<brace_t*, parse_context> parse_brace(parse_context ctx)
{ {
brace* ret = new brace; brace_t* ret = new brace_t;
uint32_t start=ctx.i; uint32_t start=ctx.i;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
@ -1160,9 +1204,9 @@ std::pair<brace*, parse_context> parse_brace(parse_context ctx)
// parse a function // parse a function
// must start right after the () // must start right after the ()
// then parses a brace block // then parses a brace block
std::pair<function*, parse_context> parse_function(parse_context ctx, const char* after) std::pair<function_t*, parse_context> parse_function(parse_context ctx, const char* after)
{ {
function* ret = new function; function_t* ret = new function_t;
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
if(ctx[ctx.i] != '{') if(ctx[ctx.i] != '{')
@ -1188,7 +1232,7 @@ std::pair<function*, parse_context> parse_function(parse_context ctx, const char
} }
// parse only var assigns // parse only var assigns
parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=false, std::string const& cmd="") parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=false, std::string const& cmd="")
{ {
bool forbid_assign=false; bool forbid_assign=false;
bool forbid_special=false; bool forbid_special=false;
@ -1197,7 +1241,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
if(cmdassign && (forbid_special || cmd == "export") ) if(cmdassign && (forbid_special || cmd == "export") )
forbid_special=true; forbid_special=true;
std::vector<std::pair<variable*,arg*>>* ret=&in->var_assigns; std::vector<std::pair<variable_t*,arg_t*>>* ret=&in->var_assigns;
if(cmdassign) if(cmdassign)
ret=&in->cmd_var_assigns; ret=&in->cmd_var_assigns;
@ -1233,7 +1277,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
else else
ctx.i++; ctx.i++;
arg* ta=nullptr; arg_t* ta=nullptr;
if(ctx[ctx.i] == '(') // bash var=() if(ctx[ctx.i] == '(') // bash var=()
{ {
if(!ctx.bash) if(!ctx.bash)
@ -1245,7 +1289,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
parse_error("Unallowed special assign", ctx); parse_error("Unallowed special assign", ctx);
} }
ctx.i++; ctx.i++;
auto pp=parse_arg(ctx, ")", ARG_OPTIMIZE_DEFARR); auto pp=parse_arg(ctx, ")", "", false, ARG_OPTIMIZE_DEFARR);
ta=pp.first; ta=pp.first;
ta->insert(0,"("); ta->insert(0,"(");
ta->add(")"); ta->add(")");
@ -1254,7 +1298,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
} }
else if( is_in(ctx[ctx.i], ARG_END) ) // no value : give empty value else if( is_in(ctx[ctx.i], ARG_END) ) // no value : give empty value
{ {
ta = new arg; ta = new arg_t;
} }
else else
{ {
@ -1263,6 +1307,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
ctx=pp.second; ctx=pp.second;
} }
ta->insert(0, strop); ta->insert(0, strop);
ta->forcequoted = !cmdassign;
ret->push_back(std::make_pair(vp.first, ta)); ret->push_back(std::make_pair(vp.first, ta));
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
} }
@ -1296,9 +1341,9 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
} }
// must start at read char // must start at read char
std::pair<cmd*, parse_context> parse_cmd(parse_context ctx) std::pair<cmd_t*, parse_context> parse_cmd(parse_context ctx)
{ {
cmd* ret = new cmd; cmd_t* ret = new cmd_t;
ctx = parse_cmd_varassigns(ret, ctx); ctx = parse_cmd_varassigns(ret, ctx);
@ -1311,8 +1356,8 @@ std::pair<cmd*, parse_context> parse_cmd(parse_context ctx)
parse_error("bash specific: "+wp.first, ctx); parse_error("bash specific: "+wp.first, ctx);
} }
ret->args = new arglist; ret->args = new arglist_t;
ret->args->add(new arg(wp.first)); ret->args->add(new arg_t(wp.first));
ret->is_cmdvar=true; ret->is_cmdvar=true;
ctx.i = wp.second; ctx.i = wp.second;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
@ -1337,9 +1382,9 @@ std::pair<cmd*, parse_context> parse_cmd(parse_context ctx)
// parse a case block // parse a case block
// must start right after the case // must start right after the case
// ends at } and nothing else // ends at } and nothing else
std::pair<case_block*, parse_context> parse_case(parse_context ctx) std::pair<case_t*, parse_context> parse_case(parse_context ctx)
{ {
case_block* ret = new case_block; case_t* ret = new case_t;
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
// get the treated argument // get the treated argument
@ -1361,7 +1406,7 @@ std::pair<case_block*, parse_context> parse_case(parse_context ctx)
while(ctx.i<ctx.size && !word_eq("esac", ctx, ARG_END) ) while(ctx.i<ctx.size && !word_eq("esac", ctx, ARG_END) )
{ {
// add one element // add one element
ret->cases.push_back( std::make_pair(std::vector<arg*>(), nullptr) ); ret->cases.push_back( std::make_pair(std::vector<arg_t*>(), nullptr) );
// iterator to last element // iterator to last element
auto cc = ret->cases.end()-1; auto cc = ret->cases.end()-1;
@ -1427,9 +1472,9 @@ std::pair<case_block*, parse_context> parse_case(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<if_block*, parse_context> parse_if(parse_context ctx) std::pair<if_t*, parse_context> parse_if(parse_context ctx)
{ {
if_block* ret = new if_block; if_t* ret = new if_t;
while(true) while(true)
{ {
@ -1486,9 +1531,9 @@ std::pair<if_block*, parse_context> parse_if(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<for_block*, parse_context> parse_for(parse_context ctx) std::pair<for_t*, parse_context> parse_for(parse_context ctx)
{ {
for_block* ret = new for_block; for_t* ret = new for_t;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
auto wp = get_word(ctx, ARG_END); auto wp = get_word(ctx, ARG_END);
@ -1497,7 +1542,7 @@ std::pair<for_block*, parse_context> parse_for(parse_context ctx)
{ {
parse_error( strf("Bad variable name in for clause: '%s'", wp.first.c_str()), ctx ); parse_error( strf("Bad variable name in for clause: '%s'", wp.first.c_str()), ctx );
} }
ret->var = new variable(wp.first, nullptr, true); ret->var = new variable_t(wp.first, nullptr, true);
ctx.i = wp.second; ctx.i = wp.second;
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
@ -1550,9 +1595,9 @@ std::pair<for_block*, parse_context> parse_for(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<while_block*, parse_context> parse_while(parse_context ctx) std::pair<while_t*, parse_context> parse_while(parse_context ctx)
{ {
while_block* ret = new while_block; while_t* ret = new while_t;
// cond // cond
parse_context oldctx = ctx; parse_context oldctx = ctx;
@ -1582,10 +1627,10 @@ std::pair<while_block*, parse_context> parse_while(parse_context ctx)
} }
// detect if brace, subshell, case or other // detect if brace, subshell, case or other
std::pair<block*, parse_context> parse_block(parse_context ctx) std::pair<block_t*, parse_context> parse_block(parse_context ctx)
{ {
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
block* ret = nullptr; block_t* ret = nullptr;
if(ctx.i>=ctx.size) if(ctx.i>=ctx.size)
{ {
@ -1701,11 +1746,11 @@ std::pair<block*, parse_context> parse_block(parse_context ctx)
} }
if(ret!=nullptr && ret->type != block::block_cmd) if(ret!=nullptr && ret->type != block_t::block_cmd)
{ {
uint32_t j=skip_chars(ctx, SPACES); uint32_t j=skip_chars(ctx, SPACES);
ctx.i=j; ctx.i=j;
auto pp=parse_arglist(ctx, false, &ret->redirs); // in case of redirects auto pp=parse_arglist(ctx, false, &ret->redirs, true); // in case of redirects
if(pp.first != nullptr) if(pp.first != nullptr)
{ {
delete pp.first; delete pp.first;

View file

@ -155,7 +155,7 @@ std::string get_varname(std::string const& in)
return in; return in;
} }
std::string get_varname(arg* in) std::string get_varname(arg_t* in)
{ {
if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string) if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string)
return ""; return "";
@ -170,12 +170,12 @@ bool cmd_is_argvar(std::string const& in)
return is_in_set(in, posix_cmdvar) || is_in_set(in, bash_cmdvar); return is_in_set(in, posix_cmdvar) || is_in_set(in, bash_cmdvar);
} }
bool cmd::is_argvar() bool cmd_t::is_argvar()
{ {
return is_cmdvar; return is_cmdvar;
} }
bool cmd::is(std::string const& in) bool cmd_t::is(std::string const& in)
{ {
return in == this->arg_string(0); return in == this->arg_string(0);
} }
@ -285,14 +285,14 @@ void add_unset_variables(shmain* sh, std::regex const& exclude)
varmap_get(sh, exclude); varmap_get(sh, exclude);
if(m_vars.size()>0) if(m_vars.size()>0)
{ {
cmd* unset_cmd = new cmd; cmd_t* unset_cmd = new cmd_t;
unset_cmd->add(new arg("unset")); unset_cmd->add(new arg_t("unset"));
unset_cmd->is_cmdvar=true; unset_cmd->is_cmdvar=true;
for(auto it: m_vars) for(auto it: m_vars)
{ {
unset_cmd->cmd_var_assigns.push_back(std::make_pair(new variable(it.first), nullptr)); unset_cmd->cmd_var_assigns.push_back(std::make_pair(new variable_t(it.first), nullptr));
} }
condlist* cl = new condlist(unset_cmd); condlist_t* cl = new condlist_t(unset_cmd);
sh->lst->cls.insert(sh->lst->cls.begin(), cl); sh->lst->cls.insert(sh->lst->cls.begin(), cl);
} }
} }
@ -315,7 +315,7 @@ bool r_has_env_set(_obj* in, bool* result)
return false; return false;
}; break; }; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd_t* t = dynamic_cast<cmd_t*>(in);
if(t->has_var_assign() || t->arg_string(0) == "cd") if(t->has_var_assign() || t->arg_string(0) == "cd")
*result = true; *result = true;
} }
@ -330,8 +330,8 @@ bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_variable: { case _obj::variable: {
variable* t = dynamic_cast<variable*>(in); variable_t* t = dynamic_cast<variable_t*>(in);
if(t->definition) if(t->definition)
{ {
if(!defmap->insert( std::make_pair(t->varname, 1) ).second) if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
@ -353,7 +353,7 @@ bool r_get_unsets(_obj* in, set_t* unsets)
switch(in->type) switch(in->type)
{ {
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd_t* t = dynamic_cast<cmd_t*>(in);
if(t->is("unset")) if(t->is("unset"))
{ {
for(auto it: t->cmd_var_assigns) for(auto it: t->cmd_var_assigns)
@ -373,7 +373,7 @@ bool r_get_cmd(_obj* in, countmap_t* all_cmds)
switch(in->type) switch(in->type)
{ {
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd_t* t = dynamic_cast<cmd_t*>(in);
std::string cmdname = t->arg_string(0); std::string cmdname = t->arg_string(0);
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second) if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++; (*all_cmds)[cmdname]++;
@ -388,7 +388,7 @@ bool r_get_fct(_obj* in, countmap_t* fct_map)
switch(in->type) switch(in->type)
{ {
case _obj::block_function: { case _obj::block_function: {
function* t = dynamic_cast<function*>(in); function_t* t = dynamic_cast<function_t*>(in);
if(!fct_map->insert( std::make_pair(t->name, 1) ).second) if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
(*fct_map)[t->name]++; (*fct_map)[t->name]++;
}; break; }; break;
@ -418,14 +418,14 @@ bool r_delete_fct(_obj* in, set_t* fcts)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_list: { case _obj::list: {
list* t = dynamic_cast<list*>(in); list_t* t = dynamic_cast<list_t*>(in);
for(uint32_t i=0; i<t->cls.size(); i++) for(uint32_t i=0; i<t->cls.size(); i++)
{ {
block* tb = t->cls[i]->first_block(); block_t* tb = t->cls[i]->first_block();
if(tb != nullptr && tb->type == _obj::block_function) if(tb != nullptr && tb->type == _obj::block_function)
{ {
function* fc = dynamic_cast<function*>(tb); function_t* fc = dynamic_cast<function_t*>(tb);
if(fcts->find(fc->name)!=fcts->end()) if(fcts->find(fc->name)!=fcts->end())
{ {
delete t->cls[i]; delete t->cls[i];
@ -444,16 +444,16 @@ bool r_delete_var(_obj* in, set_t* vars)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::_list: { case _obj::list: {
list* t = dynamic_cast<list*>(in); list_t* t = dynamic_cast<list_t*>(in);
for(uint32_t i=0; i<t->cls.size(); i++) for(uint32_t i=0; i<t->cls.size(); i++)
{ {
block* tb = t->cls[i]->first_block(); block_t* tb = t->cls[i]->first_block();
bool to_delete=false; bool to_delete=false;
bool has_deleted=false; bool has_deleted=false;
if(tb != nullptr && tb->type == _obj::block_cmd) if(tb != nullptr && tb->type == _obj::block_cmd)
{ {
cmd* c = dynamic_cast<cmd*>(tb); cmd_t* c = dynamic_cast<cmd_t*>(tb);
for(uint32_t j=0; j<c->var_assigns.size(); j++) for(uint32_t j=0; j<c->var_assigns.size(); j++)
{ {
@ -549,7 +549,7 @@ bool r_do_string_processor(_obj* in)
{ {
if(in->type == _obj::subarg_string) if(in->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(in); subarg_string_t* t = dynamic_cast<subarg_string_t*>(in);
auto v = get_processors(t->val); auto v = get_processors(t->val);
if(v.find("LXSH_PARSE_MINIFY") != v.end()) if(v.find("LXSH_PARSE_MINIFY") != v.end())
{ {
@ -634,9 +634,9 @@ std::string gen_json_struc(_obj* o)
std::vector<std::pair<std::string,std::string>> vec; std::vector<std::pair<std::string,std::string>> vec;
switch(o->type) switch(o->type)
{ {
case _obj::_variable : case _obj::variable :
{ {
variable* t = dynamic_cast<variable*>(o); variable_t* t = dynamic_cast<variable_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) );
vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname))); vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname)));
vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition))); vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition)));
@ -646,28 +646,29 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) ); vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
break; break;
} }
case _obj::_redirect : case _obj::redirect :
{ {
redirect* t = dynamic_cast<redirect*>(o); redirect_t* t = dynamic_cast<redirect_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) );
vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op))); vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op)));
vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target))); vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target)));
vec.push_back(std::make_pair(quote_string("here_document"), gen_json_struc(t->here_document))); vec.push_back(std::make_pair(quote_string("here_document"), gen_json_struc(t->here_document)));
break; break;
} }
case _obj::_arg : case _obj::arg :
{ {
arg* t = dynamic_cast<arg*>(o); arg_t* t = dynamic_cast<arg_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) );
vec.push_back(std::make_pair(quote_string("forcequoted"), boolstring(t->forcequoted)));
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->sa) for(auto it: t->sa)
tvec.push_back(gen_json_struc(it)); tvec.push_back(gen_json_struc(it));
vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec)));
break; break;
} }
case _obj::_arglist : case _obj::arglist :
{ {
arglist* t = dynamic_cast<arglist*>(o); arglist_t* t = dynamic_cast<arglist_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->args) for(auto it: t->args)
@ -675,9 +676,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec)));
break; break;
} }
case _obj::_pipeline : case _obj::pipeline :
{ {
pipeline* t = dynamic_cast<pipeline*>(o); pipeline_t* t = dynamic_cast<pipeline_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) );
vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) ); vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
@ -686,9 +687,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec)));
break; break;
} }
case _obj::_condlist : case _obj::condlist :
{ {
condlist* t = dynamic_cast<condlist*>(o); condlist_t* t = dynamic_cast<condlist_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) );
vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) ); vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
@ -704,9 +705,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec))); vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec)));
break; break;
} }
case _obj::_list : case _obj::list :
{ {
list* t = dynamic_cast<list*>(o); list_t* t = dynamic_cast<list_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->cls) for(auto it: t->cls)
@ -716,7 +717,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_subshell : case _obj::block_subshell :
{ {
subshell* t = dynamic_cast<subshell*>(o); subshell_t* t = dynamic_cast<subshell_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) );
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst))); vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
@ -730,7 +731,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_brace : case _obj::block_brace :
{ {
brace* t = dynamic_cast<brace*>(o); brace_t* t = dynamic_cast<brace_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) );
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst))); vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
@ -759,7 +760,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_function : case _obj::block_function :
{ {
function* t = dynamic_cast<function*>(o); function_t* t = dynamic_cast<function_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) );
vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) ); vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) );
@ -774,7 +775,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_cmd : case _obj::block_cmd :
{ {
cmd* t = dynamic_cast<cmd*>(o); cmd_t* t = dynamic_cast<cmd_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) );
vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args))); vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args)));
@ -808,7 +809,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_case : case _obj::block_case :
{ {
case_block* t = dynamic_cast<case_block*>(o); case_t* t = dynamic_cast<case_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) );
vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg))); vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg)));
@ -837,7 +838,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_if : case _obj::block_if :
{ {
if_block* t = dynamic_cast<if_block*>(o); if_t* t = dynamic_cast<if_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) );
std::vector<std::string> condblocks; std::vector<std::string> condblocks;
@ -862,7 +863,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_for : case _obj::block_for :
{ {
for_block* t = dynamic_cast<for_block*>(o); for_t* t = dynamic_cast<for_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var))); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var)));
vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter))); vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter)));
@ -877,7 +878,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_while : case _obj::block_while :
{ {
while_block* t = dynamic_cast<while_block*>(o); while_t* t = dynamic_cast<while_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) );
vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) ); vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) );
vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) ); vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) );
@ -891,21 +892,21 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::subarg_variable : case _obj::subarg_variable :
{ {
variable_subarg* t = dynamic_cast<variable_subarg*>(o); subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) ); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
break; break;
} }
case _obj::subarg_subshell : case _obj::subarg_subshell :
{ {
subshell_subarg* t = dynamic_cast<subshell_subarg*>(o); subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
break; break;
} }
case _obj::subarg_procsub : case _obj::subarg_procsub :
{ {
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o); subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) );
vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) ); vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
@ -913,35 +914,35 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::subarg_arithmetic : case _obj::subarg_arithmetic :
{ {
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o); subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) );
vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) ); vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) );
break; break;
} }
case _obj::subarg_string : case _obj::subarg_string :
{ {
string_subarg* t = dynamic_cast<string_subarg*>(o); subarg_string_t* t = dynamic_cast<subarg_string_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) );
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
break; break;
} }
case _obj::arithmetic_variable : case _obj::arithmetic_variable :
{ {
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o); arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) ); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
break; break;
} }
case _obj::arithmetic_subshell : case _obj::arithmetic_subshell :
{ {
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o); arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
break; break;
} }
case _obj::arithmetic_operation : case _obj::arithmetic_operation :
{ {
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o); arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) );
vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) ); vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) );
vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) ); vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) );
@ -949,14 +950,14 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::arithmetic_parenthesis : case _obj::arithmetic_parenthesis :
{ {
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o); arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) );
vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) );
break; break;
} }
case _obj::arithmetic_number : case _obj::arithmetic_number :
{ {
number_arithmetic* t = dynamic_cast<number_arithmetic*>(o); arithmetic_number_t* t = dynamic_cast<arithmetic_number_t*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) );
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
break; break;

View file

@ -59,7 +59,7 @@ void _cd(std::string const& dir)
// -- COMMANDS -- // -- COMMANDS --
// return <name, contents>[] // return <name, contents>[]
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, parse_context ctx, std::string* ex_dir) std::vector<std::pair<std::string, std::string>> do_include_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir)
{ {
std::vector<std::pair<std::string, std::string>> ret; std::vector<std::pair<std::string, std::string>> ret;
@ -105,7 +105,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, p
} }
// //
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, parse_context ctx, std::string* ex_dir) std::pair<std::string, std::string> do_resolve_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir)
{ {
std::pair<std::string, std::string> ret; std::pair<std::string, std::string> ret;
@ -152,9 +152,9 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, parse_context
return ret; return ret;
} }
std::vector<condlist*> do_include_parse(condlist* cmd, parse_context ctx) std::vector<condlist_t*> do_include_parse(condlist_t* cmd, parse_context ctx)
{ {
std::vector<condlist*> ret; std::vector<condlist_t*> ret;
std::string dir; std::string dir;
auto incs=do_include_raw(cmd, ctx, &dir); auto incs=do_include_raw(cmd, ctx, &dir);
@ -186,9 +186,9 @@ std::vector<condlist*> do_include_parse(condlist* cmd, parse_context ctx)
} }
// if first is nullptr: is a string // if first is nullptr: is a string
std::vector<condlist*> do_resolve_parse(condlist* cmd, parse_context ctx) std::vector<condlist_t*> do_resolve_parse(condlist_t* cmd, parse_context ctx)
{ {
std::vector<condlist*> ret; std::vector<condlist_t*> ret;
std::pair<std::string,std::string> p; std::pair<std::string,std::string> p;
try try
@ -220,11 +220,11 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, parse_context ctx)
// -- OBJECT CALLS -- // -- OBJECT CALLS --
std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, parse_context ctx) std::pair< std::vector<condlist_t*> , bool > resolve_condlist(condlist_t* in, parse_context ctx)
{ {
cmd* tc = in->first_cmd(); cmd_t* tc = in->first_cmd();
if(tc == nullptr) if(tc == nullptr)
return std::make_pair(std::vector<condlist*>(), false); return std::make_pair(std::vector<condlist_t*>(), false);
std::string const& strcmd=tc->arg_string(0); std::string const& strcmd=tc->arg_string(0);
@ -233,17 +233,17 @@ std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, parse_
else if(g_resolve && strcmd == "%resolve") else if(g_resolve && strcmd == "%resolve")
return std::make_pair(do_resolve_parse(in, ctx), true); return std::make_pair(do_resolve_parse(in, ctx), true);
else else
return std::make_pair(std::vector<condlist*>(), false); return std::make_pair(std::vector<condlist_t*>(), false);
} }
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bool forcequote=false) std::pair< std::vector<arg_t*> , bool > resolve_arg(arg_t* in, parse_context ctx, bool forcequote=false)
{ {
std::vector<arg*> ret; std::vector<arg_t*> ret;
if(in == nullptr) if(in == nullptr)
{ {
return std::make_pair(ret, false); return std::make_pair(ret, false);
} }
arg* ta=nullptr; arg_t* ta=nullptr;
bool has_resolved=false; bool has_resolved=false;
uint32_t j=0; uint32_t j=0;
for(uint32_t i=0 ; i<in->size() ; i++) for(uint32_t i=0 ; i<in->size() ; i++)
@ -251,11 +251,11 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bo
if(in->sa[i]->type != _obj::subarg_subshell) // skip if not subshell if(in->sa[i]->type != _obj::subarg_subshell) // skip if not subshell
continue; continue;
subshell_subarg* tsh = dynamic_cast<subshell_subarg*>(in->sa[i]); subarg_subshell_t* tsh = dynamic_cast<subarg_subshell_t*>(in->sa[i]);
if(tsh->sbsh->lst->cls.size() != 1) // skip if not one cl if(tsh->sbsh->lst->cls.size() != 1) // skip if not one cl
continue; continue;
condlist* tc = tsh->sbsh->lst->cls[0]; condlist_t* tc = tsh->sbsh->lst->cls[0];
cmd* c = tc->first_cmd(); cmd_t* c = tc->first_cmd();
if(c == nullptr) // skip if not cmd if(c == nullptr) // skip if not cmd
continue; continue;
std::string strcmd=c->arg_string(0); std::string strcmd=c->arg_string(0);
@ -294,7 +294,7 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bo
{ {
// replace with new subarg // replace with new subarg
delete in->sa[i]; delete in->sa[i];
in->sa[i] = new string_subarg(fulltext); in->sa[i] = new subarg_string_t(fulltext);
} }
else else
{ {
@ -305,21 +305,21 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bo
if(strargs.size() == 1) if(strargs.size() == 1)
val = strargs[0]; val = strargs[0];
delete in->sa[i]; delete in->sa[i];
in->sa[i] = new string_subarg(val); in->sa[i] = new subarg_string_t(val);
} }
else // pack else // pack
{ {
if(ta == nullptr) if(ta == nullptr)
ta = new arg; ta = new arg_t;
ta->sa.insert(ta->sa.end(), in->sa.begin()+j, in->sa.begin()+i); ta->sa.insert(ta->sa.end(), in->sa.begin()+j, in->sa.begin()+i);
ta->add(new string_subarg(strargs[i])); ta->add(new subarg_string_t(strargs[i]));
j=i+1; j=i+1;
delete in->sa[i]; delete in->sa[i];
for(uint32_t li=1 ; li<strargs.size() ; li++) for(uint32_t li=1 ; li<strargs.size() ; li++)
{ {
ret.push_back(ta); ret.push_back(ta);
ta = new arg; ta = new arg_t;
ta->add(new string_subarg(strargs[li])); ta->add(new subarg_string_t(strargs[li]));
} }
} // end pack } // end pack
@ -350,9 +350,9 @@ bool r_resolve(_obj* o, parse_context* ct)
// check every sub-object // check every sub-object
// execute resolve manually // execute resolve manually
// instruct parent resolve to not resolve // instruct parent resolve to not resolve
case _obj::_list : case _obj::list :
{ {
auto t = dynamic_cast<list*>(o); auto t = dynamic_cast<list_t*>(o);
for(uint32_t i=0 ; i<t->cls.size() ; i++) for(uint32_t i=0 ; i<t->cls.size() ; i++)
{ {
auto r=resolve_condlist(t->cls[i], *ct); auto r=resolve_condlist(t->cls[i], *ct);
@ -373,9 +373,9 @@ bool r_resolve(_obj* o, parse_context* ct)
} }
return false; return false;
} break; } break;
case _obj::_arglist : case _obj::arglist :
{ {
auto t = dynamic_cast<arglist*>(o); auto t = dynamic_cast<arglist_t*>(o);
for(uint32_t i=0 ; i<t->size() ; i++) for(uint32_t i=0 ; i<t->size() ; i++)
{ {
auto r=resolve_arg(t->args[i], *ct); auto r=resolve_arg(t->args[i], *ct);
@ -397,7 +397,7 @@ bool r_resolve(_obj* o, parse_context* ct)
} break; } break;
case _obj::block_cmd : case _obj::block_cmd :
{ {
auto t = dynamic_cast<cmd*>(o); auto t = dynamic_cast<cmd_t*>(o);
for(auto it: t->var_assigns) // var assigns for(auto it: t->var_assigns) // var assigns
{ {
resolve_arg(it.second, *ct, true); // force quoted resolve_arg(it.second, *ct, true); // force quoted
@ -415,7 +415,7 @@ bool r_resolve(_obj* o, parse_context* ct)
}; break; }; break;
case _obj::block_case : case _obj::block_case :
{ {
auto t = dynamic_cast<case_block*>(o); auto t = dynamic_cast<case_t*>(o);
for(auto sc: t->cases) for(auto sc: t->cases)
{ {
resolve_arg(t->carg, *ct, true); // force quoted resolve_arg(t->carg, *ct, true); // force quoted

View file

@ -7,7 +7,7 @@
const std::map<const std::string, const lxsh_fct> lxsh_extend_fcts = { const std::map<const std::string, const lxsh_fct> lxsh_extend_fcts = {
{ "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(K*8). Default 2", RANDOM_SH} }, { "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(K*8). Default 2", RANDOM_SH} },
{ "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} }, { "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} },
{ "_lxsh_random_tmpfile", { "[N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} } { "_lxsh_random_tmpfile", { "[PREFIX] [N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} }
} }
}; };

View file

@ -5,13 +5,11 @@
#include <unistd.h> #include <unistd.h>
std::string g_origin=""; const std::string cmd_t::empty_string="";
const std::string cmd::empty_string=""; condlist_t::condlist_t(block_t* bl)
condlist::condlist(block* bl)
{ {
type=_obj::_condlist; type=_obj::condlist;
parallel=false; parallel=false;
this->add(new pipeline(bl)); this->add(new pipeline_t(bl));
} }

View file

@ -7,107 +7,107 @@
// makers // makers
arg* make_arg(std::string const& in) arg_t* make_arg(std::string const& in)
{ {
return parse_arg(make_context(in)).first; return parse_arg(make_context(in)).first;
} }
cmd* make_cmd(std::vector<const char*> const& args) cmd_t* make_cmd(std::vector<const char*> const& args)
{ {
cmd* ret = new cmd; cmd_t* ret = new cmd_t;
ret->args = new arglist; ret->args = new arglist_t;
for(auto it: args) for(auto it: args)
ret->args->add(new arg(it)); ret->args->add(new arg_t(it));
return ret; return ret;
} }
cmd* make_cmd(std::vector<std::string> const& args) cmd_t* make_cmd(std::vector<std::string> const& args)
{ {
cmd* ret = new cmd; cmd_t* ret = new cmd_t;
ret->args = new arglist; ret->args = new arglist_t;
for(auto it: args) for(auto it: args)
ret->args->add(new arg(it)); ret->args->add(new arg_t(it));
return ret; return ret;
} }
cmd* make_cmd(std::vector<arg*> const& args) cmd_t* make_cmd(std::vector<arg_t*> const& args)
{ {
cmd* ret = new cmd; cmd_t* ret = new cmd_t;
ret->args = new arglist; ret->args = new arglist_t;
for(auto it: args) for(auto it: args)
ret->args->add(it); ret->args->add(it);
return ret; return ret;
} }
cmd* make_cmd(std::string const& in) cmd_t* make_cmd(std::string const& in)
{ {
return parse_cmd(make_context(in)).first; return parse_cmd(make_context(in)).first;
} }
pipeline* make_pipeline(std::vector<block*> const& bls) pipeline_t* make_pipeline(std::vector<block_t*> const& bls)
{ {
pipeline* ret = new pipeline; pipeline_t* ret = new pipeline_t;
for(auto it: bls) for(auto it: bls)
ret->add(it); ret->add(it);
return ret; return ret;
} }
pipeline* make_pipeline(std::string const& in) pipeline_t* make_pipeline(std::string const& in)
{ {
return parse_pipeline(make_context(in)).first; return parse_pipeline(make_context(in)).first;
} }
condlist* make_condlist(std::string const& in) condlist_t* make_condlist(std::string const& in)
{ {
return parse_condlist(make_context(in)).first; return parse_condlist(make_context(in)).first;
} }
list* make_list(std::string const& in) list_t* make_list(std::string const& in)
{ {
auto t = parse_list_until(make_context(in)); auto t = parse_list_until(make_context(in));
return std::get<0>(t); return std::get<0>(t);
} }
block* make_block(std::string const& in) block_t* make_block(std::string const& in)
{ {
return parse_block(make_context(in)).first; return parse_block(make_context(in)).first;
} }
cmd* make_printf(arg* in) cmd_t* make_printf(arg_t* in)
{ {
cmd* prnt = make_cmd(std::vector<const char*>({"printf", "%s\\\\n"})); cmd_t* prnt = make_cmd(std::vector<const char*>({"printf", "%s\\\\n"}));
force_quotes(in); force_quotes(in);
prnt->add(in); prnt->add(in);
return prnt; return prnt;
} }
arithmetic* make_arithmetic(arg* a) arithmetic_t* make_arithmetic(arg_t* a)
{ {
if(a->sa.size() != 1) if(a->sa.size() != 1)
{ {
cmd* prnt = make_printf(a); cmd_t* prnt = make_printf(a);
return new subshell_arithmetic(new subshell(prnt)); return new arithmetic_subshell_t(new subshell_t(prnt));
} }
arithmetic* ret=nullptr; arithmetic_t* ret=nullptr;
switch(a->sa[0]->type) { switch(a->sa[0]->type) {
case _obj::subarg_string : { case _obj::subarg_string : {
string_subarg* t = dynamic_cast<string_subarg*>(a->sa[0]); subarg_string_t* t = dynamic_cast<subarg_string_t*>(a->sa[0]);
ret = new number_arithmetic(t->val); ret = new arithmetic_number_t(t->val);
}; break; }; break;
case _obj::subarg_variable : { case _obj::subarg_variable : {
variable_subarg* t = dynamic_cast<variable_subarg*>(a->sa[0]); subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(a->sa[0]);
ret = new variable_arithmetic(t->var); ret = new arithmetic_variable_t(t->var);
t->var = nullptr; t->var = nullptr;
}; break; }; break;
case _obj::subarg_subshell : { case _obj::subarg_subshell : {
subshell_subarg* t = dynamic_cast<subshell_subarg*>(a->sa[0]); subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(a->sa[0]);
ret = new subshell_arithmetic(t->sbsh); ret = new arithmetic_subshell_t(t->sbsh);
t->sbsh = nullptr; t->sbsh = nullptr;
}; break; }; break;
case _obj::subarg_arithmetic : { case _obj::subarg_arithmetic : {
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(a->sa[0]); subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(a->sa[0]);
ret = t->arith; ret = t->arith;
t->arith = nullptr; t->arith = nullptr;
}; break; }; break;
@ -117,22 +117,22 @@ arithmetic* make_arithmetic(arg* a)
return ret; return ret;
} }
arithmetic* make_arithmetic(arg* arg1, std::string op, arg* arg2) arithmetic_t* make_arithmetic(arg_t* arg1, std::string op, arg_t* arg2)
{ {
return new operation_arithmetic(op, make_arithmetic(arg1), make_arithmetic(arg2)); return new arithmetic_operation_t(op, make_arithmetic(arg1), make_arithmetic(arg2));
} }
// copy // copy
arg* copy(arg* in) { arg_t* copy(arg_t* in) {
std::string str = in->generate(0); std::string str = in->generate(0);
return parse_arg(make_context(str)).first; return parse_arg(make_context(str)).first;
} }
// modifiers // modifiers
void force_quotes(arg* in) void force_quotes(arg_t* in)
{ {
for(uint32_t i=0; i < in->sa.size() ; i++) for(uint32_t i=0; i < in->sa.size() ; i++)
{ {
@ -146,24 +146,24 @@ void force_quotes(arg* in)
} }
} }
void add_quotes(arg* in) void add_quotes(arg_t* in)
{ {
for(uint32_t i=0; i < in->sa.size() ; i++) for(uint32_t i=0; i < in->sa.size() ; i++)
in->sa[i]->quoted=true; in->sa[i]->quoted=true;
in->insert(0, new string_subarg("\"")); in->insert(0, new subarg_string_t("\""));
in->add("\""); in->add("\"");
} }
// ** TESTERS ** // // ** TESTERS ** //
bool arg_has_char(char c, arg* in) bool arg_has_char(char c, arg_t* in)
{ {
for(auto it: in->sa) for(auto it: in->sa)
{ {
if(it->type == _obj::subarg_string) if(it->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(it); subarg_string_t* t = dynamic_cast<subarg_string_t*>(it);
if(t->val.find(c) != std::string::npos) if(t->val.find(c) != std::string::npos)
return true; return true;
} }
@ -171,7 +171,7 @@ bool arg_has_char(char c, arg* in)
return false; return false;
} }
bool possibly_expands(arg* in) bool possibly_expands(arg_t* in)
{ {
for(auto it: in->sa) for(auto it: in->sa)
if( (it->type == _obj::subarg_subshell || it->type == _obj::subarg_variable ) && it->quoted == false) if( (it->type == _obj::subarg_subshell || it->type == _obj::subarg_variable ) && it->quoted == false)
@ -179,7 +179,7 @@ bool possibly_expands(arg* in)
return false; return false;
} }
bool possibly_expands(arglist* in) bool possibly_expands(arglist_t* in)
{ {
for(auto it: in->args) for(auto it: in->args)
if(possibly_expands(it)) if(possibly_expands(it))
@ -193,7 +193,7 @@ bool possibly_expands(arglist* in)
// property getters // property getters
bool cmd::has_var_assign() bool cmd_t::has_var_assign()
{ {
if(this->args == nullptr || this->args->size() == 0) if(this->args == nullptr || this->args->size() == 0)
{ {
@ -202,7 +202,7 @@ bool cmd::has_var_assign()
return this->is_argvar(); return this->is_argvar();
} }
size_t cmd::arglist_size() size_t cmd_t::arglist_size()
{ {
if(args==nullptr) if(args==nullptr)
return 0; return 0;
@ -212,26 +212,33 @@ size_t cmd::arglist_size()
// string getters // string getters
bool arg::is_string() bool arg_t::is_string()
{ {
return sa.size() == 1 && sa[0]->type == _obj::subarg_string; return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
} }
std::string arg::string() std::string arg_t::string()
{ {
if(!this->is_string()) if(!this->is_string())
return ""; return "";
return dynamic_cast<string_subarg*>(sa[0])->val; return dynamic_cast<subarg_string_t*>(sa[0])->val;
} }
std::string arg::first_sa_string() std::string arg_t::first_sa_string()
{ {
if(sa.size() <=0 || sa[0]->type != _obj::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<subarg_string_t*>(sa[0])->val;
} }
bool arg::can_expand() std::string arglist_t::first_arg_string()
{
if(args.size()<=0 || args[0] == nullptr)
return "";
return args[0]->string();
}
bool arg_t::can_expand()
{ {
for(auto it: sa) for(auto it: sa)
{ {
@ -241,7 +248,7 @@ bool arg::can_expand()
return false; return false;
} }
bool arglist::can_expand() bool arglist_t::can_expand()
{ {
bool arg_expands=false; bool arg_expands=false;
for(auto it: args) for(auto it: args)
@ -253,7 +260,7 @@ bool arglist::can_expand()
return false; return false;
} }
std::vector<std::string> arglist::strargs(uint32_t start) std::vector<std::string> arglist_t::strargs(uint32_t start)
{ {
std::vector<std::string> ret; std::vector<std::string> ret;
bool t=opt_minify; bool t=opt_minify;
@ -266,16 +273,16 @@ std::vector<std::string> arglist::strargs(uint32_t start)
return ret; return ret;
} }
std::string const& cmd::arg_string(uint32_t n) std::string const& cmd_t::arg_string(uint32_t n)
{ {
if(args!=nullptr && args->args.size()>n && args->args[n]->sa.size() == 1 && args->args[n]->sa[0]->type == _obj::subarg_string) if(args!=nullptr && args->args.size()>n && args->args[n]->sa.size() == 1 && args->args[n]->sa[0]->type == _obj::subarg_string)
return dynamic_cast<string_subarg*>(args->args[n]->sa[0])->val; return dynamic_cast<subarg_string_t*>(args->args[n]->sa[0])->val;
return cmd::empty_string; return cmd_t::empty_string;
} }
// subobject getters // subobject getters
block* condlist::first_block() block_t* condlist_t::first_block()
{ {
if(pls.size() > 0 && pls[0]->cmds.size() > 0) if(pls.size() > 0 && pls[0]->cmds.size() > 0)
return (pls[0]->cmds[0]); return (pls[0]->cmds[0]);
@ -283,40 +290,40 @@ block* condlist::first_block()
return nullptr; return nullptr;
} }
cmd* condlist::first_cmd() cmd_t* condlist_t::first_cmd()
{ {
if(pls.size() > 0 && pls[0]->cmds.size() > 0 && pls[0]->cmds[0]->type == _obj::block_cmd) if(pls.size() > 0 && pls[0]->cmds.size() > 0 && pls[0]->cmds[0]->type == _obj::block_cmd)
return dynamic_cast<cmd*>(pls[0]->cmds[0]); return dynamic_cast<cmd_t*>(pls[0]->cmds[0]);
else else
return nullptr; return nullptr;
} }
cmd* brace::single_cmd() cmd_t* brace_t::single_cmd()
{ {
if( lst->cls.size() == 1 && // only one condlist if( lst->cls.size() == 1 && // only one condlist
lst->cls[0]->pls.size() == 1 && // only one pipeline lst->cls[0]->pls.size() == 1 && // only one pipeline
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
return dynamic_cast<cmd*>(lst->cls[0]->pls[0]->cmds[0]); // return command return dynamic_cast<cmd_t*>(lst->cls[0]->pls[0]->cmds[0]); // return command
return nullptr; return nullptr;
} }
cmd* subshell::single_cmd() cmd_t* subshell_t::single_cmd()
{ {
if( lst->cls.size() == 1 && // only one condlist if( lst->cls.size() == 1 && // only one condlist
lst->cls[0]->pls.size() == 1 && // only one pipeline lst->cls[0]->pls.size() == 1 && // only one pipeline
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
return dynamic_cast<cmd*>(lst->cls[0]->pls[0]->cmds[0]); // return command return dynamic_cast<cmd_t*>(lst->cls[0]->pls[0]->cmds[0]); // return command
return nullptr; return nullptr;
} }
cmd* block::single_cmd() cmd_t* block_t::single_cmd()
{ {
if(this->type == _obj::block_subshell) if(this->type == _obj::block_subshell)
return dynamic_cast<subshell*>(this)->single_cmd(); return dynamic_cast<subshell_t*>(this)->single_cmd();
if(this->type == _obj::block_brace) if(this->type == _obj::block_brace)
return dynamic_cast<brace*>(this)->single_cmd(); return dynamic_cast<brace_t*>(this)->single_cmd();
return nullptr; return nullptr;
} }
@ -324,15 +331,15 @@ cmd* block::single_cmd()
// simple setters // simple setters
void arg::set(std::string const& str) void arg_t::set(std::string const& str)
{ {
for(auto it: sa) for(auto it: sa)
delete it; delete it;
sa.resize(0); sa.resize(0);
sa.push_back(new string_subarg(str)); sa.push_back(new subarg_string_t(str));
} }
void condlist::prune_first_cmd() void condlist_t::prune_first_cmd()
{ {
if(pls.size()>0 && pls[0]->cmds.size()>0) if(pls.size()>0 && pls[0]->cmds.size()>0)
{ {
@ -343,40 +350,40 @@ void condlist::prune_first_cmd()
// add/extend // add/extend
void arg::insert(uint32_t i, std::string const& in) void arg_t::insert(uint32_t i, std::string const& in)
{ {
if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string) if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]); subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i-1]);
t->val += in; t->val += in;
} }
else if(i<sa.size() && sa[i]->type == _obj::subarg_string) else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]); subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i]);
t->val = in + t->val; t->val = in + t->val;
} }
else else
sa.insert(sa.begin()+i, new string_subarg(in)); sa.insert(sa.begin()+i, new subarg_string_t(in));
} }
void arg::add(std::string const& in) void arg_t::add(std::string const& in)
{ {
this->insert(this->size(), in); this->insert(this->size(), in);
} }
void arg::insert(uint32_t i, subarg* val) void arg_t::insert(uint32_t i, subarg_t* val)
{ {
if(val->type == _obj::subarg_string) if(val->type == _obj::subarg_string)
{ {
string_subarg* tval = dynamic_cast<string_subarg*>(val); subarg_string_t* tval = dynamic_cast<subarg_string_t*>(val);
if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string) if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]); subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i-1]);
t->val += tval->val; t->val += tval->val;
delete val; delete val;
} }
else if(i<sa.size() && sa[i]->type == _obj::subarg_string) else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
{ {
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]); subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i]);
t->val = tval->val + t->val; t->val = tval->val + t->val;
delete val; delete val;
} }
@ -386,43 +393,43 @@ void arg::insert(uint32_t i, subarg* val)
else else
sa.insert(sa.begin()+i, val); sa.insert(sa.begin()+i, val);
} }
void arg::insert(uint32_t i, arg const& a) void arg_t::insert(uint32_t i, arg_t const& a)
{ {
sa.insert(sa.begin()+i, a.sa.begin(), a.sa.end()); sa.insert(sa.begin()+i, a.sa.begin(), a.sa.end());
} }
void arglist::insert(uint32_t i, arg* val) void arglist_t::insert(uint32_t i, arg_t* val)
{ {
args.insert(args.begin()+i, val); args.insert(args.begin()+i, val);
} }
void arglist::insert(uint32_t i, arglist const& lst) void arglist_t::insert(uint32_t i, arglist_t const& lst)
{ {
args.insert(args.begin()+i, lst.args.begin(), lst.args.end()); args.insert(args.begin()+i, lst.args.begin(), lst.args.end());
} }
void cmd::add(arg* in) void cmd_t::add(arg_t* in)
{ {
if(args==nullptr) if(args==nullptr)
args = new arglist; args = new arglist_t;
args->add(in); args->add(in);
} }
void condlist::add(pipeline* pl, bool or_op) void condlist_t::add(pipeline_t* pl, bool or_op)
{ {
if(pls.size() > 0) if(pls.size() > 0)
or_ops.push_back(or_op); or_ops.push_back(or_op);
pls.push_back(pl); pls.push_back(pl);
} }
void list::insert(uint32_t i, condlist* val) void list_t::insert(uint32_t i, condlist_t* val)
{ {
if(i<0) if(i<0)
cls.insert(cls.end(), val); cls.insert(cls.end(), val);
else else
cls.insert(cls.begin()+i, val); cls.insert(cls.begin()+i, val);
} }
void list::insert(uint32_t i, list const& lst) void list_t::insert(uint32_t i, list_t const& lst)
{ {
if(i<0) if(i<0)
cls.insert(cls.end(), lst.cls.begin(), lst.cls.end()); cls.insert(cls.end(), lst.cls.begin(), lst.cls.end());
@ -440,7 +447,7 @@ void shmain::concat(shmain* in)
// special modifiers // special modifiers
void condlist::negate() void condlist_t::negate()
{ {
// invert commands // invert commands
for(uint32_t i=0; i<pls.size(); i++) for(uint32_t i=0; i<pls.size(); i++)

47
test/a.bash Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env bash
diff <(echo a) <(echo b)
write_to_file() { echo "$2" > "$1"; }
write_to_file >(grep bar) bar
wait $!
echo a &> /tmp/foo
echo b >& /tmp/bar
echo c &>> /tmp/foo
cat /tmp/bar /tmp/foo
rm /tmp/bar /tmp/foo
TOTO="foo
bar"
grep ar <<< ar$TOTO
declare -a A
A=("fo o" bar)
echo ${A[1]}
declare -A B
B[foo]=ta
B[bar]=tu
echo ${B[foo]}
echo ${B[bar]}
echo ${B[*]}
C=([foo]=bar [bar]=foo)
echo ${C[foo]}
echo ${C[bar]}
echo ${C[*]}
BAR=FOO
echo ${!BAR}
[[ $DEBUG == true ]] && echo debug
a=a
[[ $a = a && foo = fo* && bar =~ b.r || 2 < 3 ]]
for I in A B C ; do
echo "$I"
done > >(cat)

4
test/arithmetic.sh Normal file
View file

@ -0,0 +1,4 @@
#!/bin/sh
echo $(( (2+1)*3 ))
echo $(( $((2+1))*3 ))

38
test/array.bash Normal file
View file

@ -0,0 +1,38 @@
#!/bin/bash
TOTO=(toto tata)
TOTO[0]=titi
TOTO[1]+=tu
echo ${TOTO[0]}
echo ${TOTO[1]}
echo ${TOTO[*]}
TOTO+=(2)
echo $((TOTO[2]+1))
echo $((${TOTO[2]}+2))
declare -a TUTU
TUTU=(titi "tu tu")
echo ${TUTU[0]}
echo ${TUTU[1]}
echo ${TUTU[*]}
echo "${TUTU[*]}"
declare -A A
A[to]=ta
A[ti]=tu
echo ${A[to]}
echo ${A[ti]}
echo ${A[*]}
declare -A B
B=([to]=ta [ti]=tu)
echo ${B[to]}
echo ${B[ti]}
echo ${B[*]}
echo "${B[*]}"
toto=tata
C=()
C+=($toto)
echo ${C[@]}

7
test/backtick.sh Normal file
View file

@ -0,0 +1,7 @@
#!/bin/sh
echo $(echo toto)
echo $(printf %s\\n tata)
echo `echo titi`
echo `printf '%s\\n' tutu`

7
test/brace.sh Normal file
View file

@ -0,0 +1,7 @@
#!/bin/sh
{ echo tata ; echo a; } | sed 's|a|toto|g'
echo a | { grep a && echo b; }
{ { echo tata ; } }

8
test/braceexp.bash Normal file
View file

@ -0,0 +1,8 @@
#!/usr/bin/bash
echo tot{a,o,i}
echo {1..10}
echo {0..10..2}
echo {1..10..2}
echo tot{a,o,i}{1..3}tata
echo :{{a..z},{A..Z}}

17
test/case.sh Normal file
View file

@ -0,0 +1,17 @@
echo "$*" | case $1 in
to*) echo toto ;;
tata) echo wew tata ;;
a | b)
echo titi
;;
*)
cat ;;
esac
case foo in bar)echo a;;foo)echo b;esac
case foo in bar)echo a;;foo)echo b
esac
case far in foo) echo a;;bar)
esac

5
test/comment.sh Normal file
View file

@ -0,0 +1,5 @@
#!/bin/sh
echo toto#
echo toto#tata
echo toto #tata

22
test/complex.sh Normal file
View file

@ -0,0 +1,22 @@
while [ -z "$I" ]
do
case $U in
*)echo toto;I=y
esac
done
echo "$I"
case toto in
tutu) ;;
toto)
cat << EOF
toto
EOF
;;
tata)
esac
echo to 2>&1
echo to2 >&1
echo to$(echo 2) >&1

50
test/debashify.bash Normal file
View file

@ -0,0 +1,50 @@
#!/bin/bash
readonly tutu titi=tata
echo "$tutu $titi"
diff <(echo a) <(echo b)
write_to_file() { echo "$2" > "$1"; }
write_to_file >(grep tutu) tutu
wait $!
echo a &> /tmp/toto
echo b >& /tmp/tata
echo c &>> /tmp/toto
cat /tmp/tata /tmp/toto
rm /tmp/tata /tmp/toto
TOTO="ta
to"
grep ta <<< toto$TOTO
TATA=ti
TATA+=tu
echo $TATA
[[ $DEBUG == true ]] && echo debug
[ $((RANDOM+RANDOM)) -gt 0 ]
echo randomstat: $?
a=a
[[ $a = a && foo = fo* && bar =~ b.r || 2 < 3 ]]
echo $?
N=1
TOTO=tatitu
echo "${TOTO:2}"
echo "${TOTO:$N:2}"
echo ${TOTO:-tutu}
echo ${TITI:-bar}
TATA=TOTO
echo ${!TATA}
for I in A B C ; do
echo "$I"
done 2>&1 > >(grep A)

78
test/dequote.sh Normal file
View file

@ -0,0 +1,78 @@
#!/bin/sh
toto=tutu
tata=titi
echo "toto tata titi"
echo "toto"
echo "tata"titi
echo "ta ta"
echo "$toto"tata
echo "$toto"
echo $toto"tata"
echo $"toto"
toto="$toto"
toto="$toto"tata
echo "$toto"
toto="tata"$tata
echo "$toto"
toto=$toto"tata"
echo "$toto"
toto="$toto".tata
echo "$toto"
tata="ta ta"
echo "$tata"
echo "$"
echo \$
toto=tutu
tata=titi
echo 'toto tata titi'
echo 'toto'
echo 'tata'titi
echo 'ta ta'
echo '$toto'tata
echo '$toto'
echo $toto'tata'
echo $'toto'
toto='$toto'
toto='$toto'tata
echo '$toto'
toto='tata'$tata
echo '$toto'
toto=$toto'tata'
echo '$toto'
toto='$toto'.tata
echo '$toto'
tata='ta ta'
echo '$tata'
echo '$'
cat << EOF
"toto"
EOF
printf "%s\n" "" ""'' "toto"

12
test/echo.bash Normal file
View file

@ -0,0 +1,12 @@
#!/bin/bash
echo -n titi:
echo -e 'tata\n'
echo -E 'tutu\n'
echo -n tata tutu tete
toto="to to"
echo $toto
echo to $toto

1
test/err/brace.sh Normal file
View file

@ -0,0 +1 @@
{ ; }

12
test/err/err.bash Normal file
View file

@ -0,0 +1,12 @@
#!/bin/bash
var[a
read var+=a
export var+=a
export var=()
[[ a = b ]] toto
echo >() <()
function toto-titi{ true; }

66
test/err/err.sh Normal file
View file

@ -0,0 +1,66 @@
#!/bin/sh
read var=a
var+=a
var=(foo)
$((var~2))
${!var}
${~}
${#var-a}
`echo \`echo\` `
$(( (var) )
>& /dev/null
echo &> /dev/null
cat 2< file
cat <<< var
echo >
echo &| cat
echo |& cat
[[ a = b ]] foo
()
fct() abc
{ ; }
fct() { }
typeset var
var=val read var
case foo ; esac
case foo in aiae ; esac
case foo in ) ; esac
case foo in a) ; b) esac
for 2 in a ; do true ; done
for foo do ; do true ; done
for foo & ; do true ; done
for I in ; true ; done
while
do true ; done
while true ; do
done
if true ;then
fi
if
then true ; fi
if true ; then true ; else
fi
fct-foo() { true; }
function foo { true; }
{ foo; } bar

11
test/fct.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
toto() {
echo toto
}
tata () {
echo tata
}
toto

18
test/for.sh Normal file
View file

@ -0,0 +1,18 @@
#!/bin/sh
__for_fct() {
for I in ; do
echo $I
done
}
for N
do
echo $N
done
for I in $(seq 1 10); do
echo "toto $I"
done
__for_fct toto tata

48
test/heredocument.sh Normal file
View file

@ -0,0 +1,48 @@
#!/bin/sh
cat << EOF
toto
tata
EOF
toto=toto
cat << EOF | grep toto
$toto
tata
EOF
cat << EOF
'
EOF
cat << EOF |
azjeha
kijejaze
ljksdjk
EOF
cut -c1
grep -q toto << EOF &&
toto
EOF
echo found toto
{ cat << EOF | grep toto; }
toto
tata
EOF
( cat << EOF | grep toto )
toto
tata
EOF
{ cat << EOF | grep toto && echo true; echo eyy; }
toto
tata
EOF
( cat << EOF | grep toto && echo true ; echo eyy )
toto
tata
EOF

11
test/if.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
if [ -n "$DEBUG" ]
then
echo "set"
elif [ -n "$TOTO" ]
then
echo "toto lol"
else
echo "not set"
fi

9
test/include.sh Normal file
View file

@ -0,0 +1,9 @@
#!/bin/sh
RAW="$(%include -f pipe.sh brace.sh)"
echo "$RAW"
{ %include -f pipe.sh; } | grep -q arch && echo "btw i use arch"
%include *.sh

15
test/manip.sh Normal file
View file

@ -0,0 +1,15 @@
#!/bin/sh
var="marijuana"
echo ${#var}
echo ${var-foo}
echo ${var+foo}
echo ${foo-foo}
echo ${foo+foo}
echo ${var#*a}
echo ${var##*a}
echo ${var%a*}
echo ${var%%a*}

8
test/pipe.sh Normal file
View file

@ -0,0 +1,8 @@
#!/bin/sh
grep "^ID=" /etc/os-release | cut -d '=' -f2-
echo toto | #
grep to
echo '#toto' | grep '#toto'

3
test/prompt.sh Normal file
View file

@ -0,0 +1,3 @@
#!/bin/sh
read -r prompt || echo $?

5
test/redir.sh Normal file
View file

@ -0,0 +1,5 @@
{ echo toto >&2; } 2>&1
{ echo tata; }>/dev/null
grep abc < test/redir.sh

9
test/resolve.sh Normal file
View file

@ -0,0 +1,9 @@
#!/bin/sh
echo "a$(%resolve echo tata titi)b"
echo $(%resolve cut -d ' ' -f1 /proc/uptime)s
%resolve echo "TIME=$(cut -d ' ' -f1 /proc/uptime)s;echo This was compiled at \${TIME}s uptime"
FOO=$(%resolve echo bar) echo foo

10
test/subshell.sh Normal file
View file

@ -0,0 +1,10 @@
TOTO=toto
(TOTO=tata; echo $TOTO; echo a) | sed 's|a|titi|g'
echo $TOTO
echo a | ( grep a && echo b )
echo ab | ( grep a )
pwd
(cd /)
pwd

31
test/var.sh Normal file
View file

@ -0,0 +1,31 @@
#!/bin/sh
foo()
{
echo $FOO
}
TOTO=tata
TATA=titi
echo $TOTO
echo "$TOTO $TATA$TITI"
echo "${AYE-aye}"
export TUTU=ta
foo
FOO=bar foo
BAR=foo foo
ABCD=$(FOO=true foo)
echo $ABCD
nul=/dev/null
echo toto > "$nul"
somevar=val
echo $somevar
unset somevar
echo $somevar
cat << EOF
$TOTO
EOF

23
test/while.sh Normal file
View file

@ -0,0 +1,23 @@
#!/bin/sh
I=0
while [ $I -lt 10 ]
do
I=$((I+1))
echo "$I"
done
I=0
until [ $I -eq 10 ]
do
I=$((I+1))
echo "$I"
done
I=0
while
I=$((I+1))
echo "$I"
[ $I -lt 10 ]
do true
done