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
/test
/run-tests.sh
/Zmakefile
/TODO
TODO
/lxsh
/gmon.out
gmon.out
/profiling/*
/profiling.*
/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.
> 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
@ -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 unnecessary quotes on arguments
- 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
removal of an unnecessary manipulation will not be made if the following character

View file

@ -2,12 +2,19 @@
#define MINIFY_HPP
#include "struc.hpp"
#include "processing.hpp"
#include <regex>
#include <string>
void minify_var(_obj* in, std::regex const& exclude);
void minify_fct(_obj* in, std::regex const& exclude);
std::string gen_minmap(strmap_t const& map, std::string const& prefix);
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);

View file

@ -11,7 +11,7 @@
#define SPACES " \t"
#define SEPARATORS " \t\n"
#define ARG_END " \t\n;#()&|<>"
#define ARG_END " \t\n;()&|<>"
#define VARNAME_END " \t\n;#()&|=\"'\\{}/-+"
#define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\"
#define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}"
@ -32,7 +32,7 @@
#define ARG_OPTIMIZE_MANIP "$\\`}"
#define ARG_OPTIMIZE_DEFARR "$\\`)"
#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_ALL "$\\` \t\n;#()&|<>}]\"'"
@ -97,35 +97,32 @@ inline uint32_t skip_unread_noline(parse_context const& ct) {
parse_context parse_heredocument(parse_context ctx);
// list
// std::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL);
// 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={});
std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
// 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
std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ct);
std::pair<variable*, parse_context> parse_manipulation(parse_context ct);
std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ct);
std::pair<variable_t*, parse_context> parse_manipulation(parse_context ct);
// 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
std::pair<redirect*, parse_context> parse_redirect(parse_context ct);
std::pair<redirect_t*, parse_context> parse_redirect(parse_context ct);
// 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
std::pair<block*, parse_context> parse_block(parse_context ct);
std::pair<cmd*, parse_context> parse_cmd(parse_context ct);
std::pair<function*, parse_context> parse_function(parse_context ct, const char* after="()");
std::pair<subshell*, parse_context> parse_subshell(parse_context ct);
std::pair<brace*, parse_context> parse_brace(parse_context ct);
std::pair<case_block*, parse_context> parse_case(parse_context ct);
std::pair<if_block*, parse_context> parse_if(parse_context ct);
std::pair<for_block*, parse_context> parse_for(parse_context ct);
std::pair<while_block*, parse_context> parse_while(parse_context ct);
std::pair<block_t*, parse_context> parse_block(parse_context ct);
std::pair<cmd_t*, parse_context> parse_cmd(parse_context ct);
std::pair<function_t*, parse_context> parse_function(parse_context ct, const char* after="()");
std::pair<subshell_t*, parse_context> parse_subshell(parse_context ct);
std::pair<brace_t*, parse_context> parse_brace(parse_context ct);
std::pair<case_t*, parse_context> parse_case(parse_context ct);
std::pair<if_t*, parse_context> parse_if(parse_context ct);
std::pair<for_t*, parse_context> parse_for(parse_context ct);
std::pair<while_t*, parse_context> parse_while(parse_context ct);
// 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
std::pair<condlist*, parse_context> parse_condlist(parse_context ct);
std::pair<condlist_t*, parse_context> parse_condlist(parse_context ct);
#endif //PARSE_HPP

View file

@ -9,7 +9,7 @@
#include "struc.hpp"
// 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
typedef std::map<std::string,uint32_t> countmap_t;
@ -60,7 +60,7 @@ std::regex fct_exclude_regex(std::string const& in);
// varnames
bool is_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
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
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->manip, args...);
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->here_document, args...);
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)
{
recurse(fct, it, args...);
}
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)
{
recurse(fct, it, args...);
}
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)
{
recurse(fct, it, args...);
}
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)
{
recurse(fct, it, args...);
}
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)
{
recurse(fct, it, args...);
}
break;
}
case _obj::block_subshell :
{
subshell* t = dynamic_cast<subshell*>(o);
subshell_t* t = dynamic_cast<subshell_t*>(o);
recurse(fct, t->lst, args...);
for(auto it: t->redirs)
@ -90,7 +80,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_brace :
{
brace* t = dynamic_cast<brace*>(o);
brace_t* t = dynamic_cast<brace_t*>(o);
recurse(fct, t->lst, args...);
for(auto it: t->redirs)
@ -110,7 +100,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_function :
{
function* t = dynamic_cast<function*>(o);
function_t* t = dynamic_cast<function_t*>(o);
recurse(fct, t->lst, args...);
for(auto it: t->redirs)
@ -120,7 +110,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_cmd :
{
cmd* t = dynamic_cast<cmd*>(o);
cmd_t* t = dynamic_cast<cmd_t*>(o);
recurse(fct, t->args, args...);
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_block* t = dynamic_cast<case_block*>(o);
case_t* t = dynamic_cast<case_t*>(o);
// carg
recurse(fct, t->carg, args...);
// cases
@ -160,7 +150,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_if :
{
if_block* t = dynamic_cast<if_block*>(o);
if_t* t = dynamic_cast<if_t*>(o);
// ifs
for(auto sc: t->blocks)
{
@ -179,7 +169,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_for :
{
for_block* t = dynamic_cast<for_block*>(o);
for_t* t = dynamic_cast<for_t*>(o);
// variable
recurse(fct, t->var, args...);
// iterations
@ -194,7 +184,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
case _obj::block_while :
{
while_block* t = dynamic_cast<while_block*>(o);
while_t* t = dynamic_cast<while_t*>(o);
// condition
recurse(fct, t->cond, args...);
// operations
@ -207,50 +197,50 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
}
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...);
break;
}
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...);
break;
}
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...);
break;
}
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...);
break;
}
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...);
break;
}
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...);
break;
}
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->val2, args...);
break;
}
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...);
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

View file

@ -6,8 +6,8 @@
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::pair<std::string, std::string> do_resolve_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_t* cmd, parse_context ctx, std::string* ex_dir=nullptr);
bool add_include(std::string const& file);

View file

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

View file

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

View file

@ -1,6 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
#define VERSION_STRING "v1.3.1"
#define VERSION_STRING "v1.5"
#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() {
printf "%s" "$1"
shift 1
shift 1 2>/dev/null || return
for N ; do
printf "\t%s" "$N"
done

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,9 @@
#define PIPE_READ 0
#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;
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
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;
try
@ -61,9 +61,9 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, parse_context ctx, FILE* f
// -- 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)
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))
{
@ -143,7 +143,7 @@ void parse_exec(FILE* fd, parse_context ctx)
ctx.i=skip_unread(ctx);
debashify_params debash_params;
list* t_lst=new list;
list_t* t_lst=new list_t;
if(t_lst == nullptr)
throw std::runtime_error("Alloc error");
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)
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;
FILE* ffd=0;
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());
ffd = fopen(fifopath.c_str(), "w");
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)
{
fclose(ffd);
unlink(fifopath.c_str());
if(pid != 0)
kill(pid, SIGINT);
fclose(ffd);
unlink(fifopath.c_str());
throw e;
}

View file

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

View file

@ -72,7 +72,7 @@ int main(int argc, char* argv[])
// parsing
sh = new shmain(new list);
sh = new shmain;
bool is_exec = false;
bool first_run = true;
@ -94,7 +94,14 @@ int main(int argc, char* argv[])
{
first_run=false;
// 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;
shebang = "#!/usr/bin/env bash";
@ -131,7 +138,6 @@ int main(int argc, char* argv[])
}
// parse
g_origin=file;
if(!add_include(file))
continue;
@ -140,6 +146,8 @@ int main(int argc, char* argv[])
ctx = make_context(filecontents, file, parse_bash);
if(is_exec)
{
delete sh;
sh = nullptr;
args.erase(args.begin());
return exec_process(shebang.substr(2), args, ctx);
}
@ -195,27 +203,38 @@ int main(int argc, char* argv[])
// processing before output
// minify
strmap_t varmap, fctmap;
if(options['m'])
{
opt_minify=true;
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
allmaps_get(sh, re_var_exclude, re_fct_exclude, regex_null);
minify_var( sh, re_var_exclude );
minify_fct( sh, re_fct_exclude );
varmap = minify_var( sh, re_var_exclude );
fctmap = minify_fct( sh, re_fct_exclude );
}
else if(options["minify-var"]) {
minify_var( sh, re_var_exclude );
varmap = minify_var( sh, re_var_exclude );
}
else if(options["minify-fct"]) {
minify_fct( sh, re_fct_exclude );
fctmap = minify_fct( sh, re_fct_exclude );
}
// other processing
if(options["unset-var"])
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
if(options['J'])
{

View file

@ -1,14 +1,15 @@
#include "minify.hpp"
#include <fstream>
#include "parse.hpp"
#include "recursive.hpp"
#include "processing.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)
return ret;
@ -16,7 +17,7 @@ std::vector<subarg*> cmd::subarg_vars()
{
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)
continue;
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)
{
case _obj::block_function: {
function* t = dynamic_cast<function*>(in);
function_t* t = dynamic_cast<function_t*>(in);
auto el=fctmap->find(t->name);
if(el!=fctmap->end())
t->name = el->second;
}; break;
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);
auto el=fctmap->find(cmdname);
if(el!=fctmap->end())
{
delete t->args->args[0];
t->args->args[0] = new arg(el->second);
t->args->args[0] = new arg_t(el->second);
}
}; break;
default: break;
@ -58,8 +59,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
{
switch(in->type)
{
case _obj::_variable: {
variable* t = dynamic_cast<variable*>(in);
case _obj::variable: {
variable_t* t = dynamic_cast<variable_t*>(in);
auto el=varmap->find(t->varname);
if(el!=varmap->end())
t->varname = el->second;
@ -69,8 +70,20 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
return true;
}
const char* singlequote_escape_char=" \\\t!\"()|&*?~><#";
const char* doublequote_escape_char=" \t'|&\\*()?~><#";
const char* singlequote_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 r=0;
@ -105,123 +118,203 @@ bool is_this_quote(char c, bool is_doublequote)
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;
if(val.size() <= 1)
return;
if(start_quoted) // don't handle start quoted for now
return;
if(val[0] == '"' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
return;
if(val[0] == '\'' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
return;
uint32_t i=0, j=0;
while( i < val.size() )
auto t = in->sa.begin();
// global loop
while(true)
{
bool doublequote=false;
while(i<val.size() && !( val[i] == '\'' || val[i] == '"') )
uint32_t i=0;
// one iteration loop
while(true)
{
if(val[i] == '\\')
i++;
i++;
}
if(i>=val.size()) // end before finding quote: exit
return;
if(val[i] == '"')
doublequote=true;
j=i;
i++;
if(doublequote)
{
while(i<val.size() && val[i] != '"')
bool doublequote=false;
bool prev_is_var=false;
bool end_is_var=false;
bool has_substitution=false;
std::string* strstart = nullptr;
uint32_t quotestart=0;
std::string* strend = nullptr;
uint32_t quoteend=0;
std::string* escapestr = nullptr;
uint32_t escapepos=0;
uint32_t ce=0;
// loop to find start of quote
while(true)
{
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++;
}
// 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++;
continue;
}
if(i>=val.size()) // end before finding quote: exit
return;
}
else
{
while(i<val.size() && val[i] != '\'')
// too many escapes: don't dequote
if(ce > 1) {
i++;
if(i>=val.size()) // end before finding quote: exit
return;
continue;
}
// 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)
{
switch(in->type)
{
case _obj::_arg: {
arg* t = dynamic_cast<arg*>(in);
for(uint32_t i=0; i<t->sa.size(); i++)
{
// 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()
}
case _obj::arg: {
arg_t* t = dynamic_cast<arg_t*>(in);
do_minify_quotes(t);
}; 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
redirect* t = dynamic_cast<redirect*>(in);
redirect_t* t = dynamic_cast<redirect_t*>(in);
if(t->here_document != nullptr)
{
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
void minify_var(_obj* in, std::regex const& exclude)
strmap_t minify_var(_obj* in, std::regex const& exclude)
{
// countmap_t vars;
set_t excluded;
@ -316,9 +409,10 @@ void minify_var(_obj* in, std::regex const& exclude)
// perform replace
recurse(r_replace_var, in, &varmap);
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;
set_t excluded, unsets;
@ -339,6 +433,7 @@ void minify_fct(_obj* in, std::regex const& exclude)
recurse(r_replace_fct, in, &fctmap);
require_rescan_fct();
require_rescan_cmd();
return fctmap;
}
bool delete_unused_fct(_obj* in, std::regex const& exclude)
@ -422,14 +517,14 @@ bool r_minify_empty_manip(_obj* in)
{
switch(in->type)
{
case _obj::_arg: {
arg* t = dynamic_cast<arg*>(in);
case _obj::arg: {
arg_t* t = dynamic_cast<arg_t*>(in);
for(uint32_t i=0; i<t->sa.size(); i++)
{
if(t->sa[i]->type == _obj::subarg_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 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 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];
// if its first would extend the var name: skip
if(is_alphanum(c) || c == '_')
@ -456,28 +551,34 @@ bool r_minify_empty_manip(_obj* in)
return true;
}
block* do_one_minify_single_block(block* in)
pipeline_t* do_one_minify_single_block(block_t* in)
{
block* ret=nullptr;
list* l=nullptr;
pipeline_t* ret=nullptr;
list_t* l=nullptr;
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)
l = dynamic_cast<subshell*>(in)->lst;
l = dynamic_cast<subshell_t*>(in)->lst;
if(l == nullptr)
return nullptr;
// not a single cmd/block: not applicable
if(l->cls.size() != 1 || l->cls[0]->pls.size() != 1 || l->cls[0]->pls[0]->cmds.size() != 1)
// not a single pipeline: not applicable
if(l->cls.size() != 1 || l->cls[0]->pls.size() != 1)
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(in->type == _obj::block_subshell && has_env_set(ret))
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;
}
@ -485,32 +586,47 @@ bool r_minify_single_block(_obj* in)
{
switch(in->type)
{
case _obj::_pipeline: {
case _obj::pipeline: {
bool has_operated=false;
do
{
// loop operating on current
// (if has operated, current object has changed)
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++)
{
block* ret = do_one_minify_single_block(t->cmds[i]);
pipeline_t* ret = do_one_minify_single_block(t->cmds[i]);
if(ret != nullptr) {
// concatenate redirects
for(uint32_t j=0; j<t->cmds[i]->redirs.size(); j++)
ret->redirs.insert(ret->redirs.begin()+j, t->cmds[i]->redirs[j]);
block_t* firstb = ret->cmds[0];
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
t->cmds[i]->redirs.resize(0);
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)
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
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;
}
@ -523,11 +639,54 @@ bool r_minify_single_block(_obj* in)
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)
{
r_minify_empty_manip(in);
r_minify_single_block(in);
r_minify_useless_quotes(in);
r_do_string_processor(in);
return true;
}
@ -535,4 +694,34 @@ bool r_minify(_obj* in)
void minify_generic(_obj* 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('e', "exec", false, "Directly execute script"),
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
ztd::option("\r [Debugging]"),
ztd::option('J', "json", false, "Output the json structure"),
@ -27,11 +28,13 @@ ztd::option_set options( {
ztd::option("\r [Processing]"),
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('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('I', "no-include", false, "Don't resolve %include 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("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("remove-unused", false, "Remove unused functions and variables"),
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["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 opts;
opts.add(
return std::vector<ztd::option>({
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")
);
return opts;
});
}
ztd::option_set create_resolve_opts()
{
ztd::option_set opts;
opts.add(
return std::vector<ztd::option>({
ztd::option('C', false, "Don't cd to folder this file is in"),
ztd::option('f', false, "Ignore non-zero return values")
);
return opts;
});
}
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(" - 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(" - `%%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");
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> 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> 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)
{
if(in != "")
{
ctx.data = in.c_str();
ctx.size = in.size();
}
ctx.data = in.c_str();
ctx.size = in.size();
if(filename != "")
ctx.filename = filename.c_str();
if(bash)
@ -207,9 +205,9 @@ std::pair<std::string,uint32_t> get_word(parse_context ctx, const char* end_set)
// 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;
uint32_t start=ctx.i;
@ -227,7 +225,7 @@ std::pair<variable*, parse_context> parse_var(parse_context ctx, bool specialvar
}
if(varname != "")
{
ret = new variable(varname);
ret = new variable_t(varname);
if(ctx.bash && array && ctx[ctx.i]=='[')
{
ctx.i++;
@ -264,9 +262,9 @@ std::pair<std::string, uint32_t> get_operator(parse_context ctx)
// parse an arithmetic
// ends at ))
// 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);
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;
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;
}
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]))
{
uint32_t j=ctx.i;
@ -293,27 +291,40 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++;
while(is_num(ctx[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))
{
ctx.i+=2;
auto ps = parse_subshell(ctx);
ret = new subshell_arithmetic(ps.first);
ret = new arithmetic_subshell_t(ps.first);
ctx=ps.second;
}
else if(word_eq("${", ctx))
{
ctx.i+=2;
auto pm = parse_manipulation(ctx);
ret = new variable_arithmetic(pm.first);
ret = new arithmetic_variable_t(pm.first);
ctx=pm.second;
}
else if(ctx[ctx.i] == '(')
{
ctx.i++;
auto pa = parse_arithmetic(ctx);
ret = pa.first;
ret = new arithmetic_parenthesis_t(pa.first);
ctx = pa.second;
ctx.i++;
}
@ -326,7 +337,7 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++;
}
auto pp = parse_var(ctx, specialvars, true);
ttvar = new variable_arithmetic(pp.first);
ttvar = new arithmetic_variable_t(pp.first);
ret = ttvar;
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);
}
arithmetic* val1 = ret;
arithmetic_t* val1 = ret;
ctx.i=po.second;
auto pa = parse_arithmetic(ctx);
arithmetic* val2 = pa.first;
arithmetic_t* val2 = pa.first;
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);
}
@ -366,10 +377,10 @@ std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context 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;
arg* precede = nullptr;
variable_t* ret = nullptr;
arg_t* precede = nullptr;
uint32_t start=ctx.i;
@ -382,7 +393,7 @@ std::pair<variable*, parse_context> parse_manipulation(parse_context ctx)
}
std::string t;
t+=ctx[ctx.i];
precede = new arg( t );
precede = new arg_t( t );
ctx.i++;
}
@ -418,8 +429,10 @@ std::pair<variable*, parse_context> parse_manipulation(parse_context 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] == '`' )
{
// add previous subarg
@ -440,10 +453,12 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
}
// get subshell
parse_context newct = ctx;
ctx.size=k;
newct.size=k;
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.size = tsize;
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
ctx.i+=3;
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;
ret->add(tt);
ctx = r.second;
@ -477,7 +492,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
// get subshell
ctx.i+=2;
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;
j = ctx.i;
}
@ -489,7 +504,7 @@ inline parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j
// get manipulation
ctx.i+=2;
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;
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)
ret->add(std::string(ctx.data+j, ctx.i-j));
// add var
ret->add(new variable_subarg(r.first, is_quoted));
ret->add(new subarg_variable_t(r.first, is_quoted));
ctx = r.second;
j = ctx.i;
}
@ -539,9 +554,9 @@ bool _optimize_skip_arg(parse_context& ctx, const char* str) {
// parse one argument
// must start at a read char
// 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
uint32_t j=ctx.i,q=ctx.i;
@ -634,7 +649,6 @@ parse_context parse_heredocument(parse_context ctx)
{
ctx.i = ctx.size;
}
// std::string tmpparse=std::string(ctx.data+j, ctx.i-j);
parse_context newctx = make_context(ctx, j);
newctx.size = ctx.i;
auto pval = parse_arg(newctx , NULL, NULL, false, ARG_OPTIMIZE_NULL);
@ -650,7 +664,19 @@ parse_context parse_heredocument(parse_context 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 needs_arg=false;
@ -737,9 +763,9 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
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);
if(needs_arg)
{
@ -775,8 +801,12 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
}
else
{
auto pa = parse_arg(ctx);
ret->target = pa.first;
std::pair<arg_t*, parse_context> pa;
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;
}
}
@ -793,9 +823,9 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
// must start at a read char
// first char has to be read
// 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
{
@ -806,14 +836,14 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
while(true)
{
if(ret == nullptr)
ret = new arglist;
ret = new arglist_t;
auto pp=parse_arg(ctx, SEPARATORS, NULL, true, ARG_OPTIMIZE_BASHTEST);
ret->add(pp.first);
ctx = pp.second;
ctx.i = skip_chars(ctx, SEPARATORS);
if(word_eq("]]", ctx, ARG_END))
{
ret->add(new arg("]]"));
ret->add(new arg_t("]]"));
ctx.i+=2;
ctx.i = skip_chars(ctx, SPACES);
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.bash)
{
parse_error(strf("bash specific: %c()", ctx[ctx.i]), ctx);
}
bool is_output = ctx[ctx.i] == '>';
ctx.i+=2;
auto pa=parse_bash_procsub(ctx);
if(ret == nullptr)
ret = new arglist;
auto ps = parse_subshell(ctx);
ret->add(new arg(new procsub_subarg(is_output, ps.first)));
ctx=ps.second;
ret = new arglist_t;
ret->add(pa.first);
ctx=pa.second;
}
else if(redirs!=nullptr)
{
@ -871,10 +895,12 @@ std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_er
}
else
{
argparse:
if(ret == nullptr)
ret = new arglist;
argparse: ;
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);
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
// separated by |
// 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))
{
ret->negated = true;
ctx.i++;
ctx.i=skip_chars(ctx, SPACES);
while(true) {
auto wp = get_word(ctx, ARG_END);
if(ctx[ctx.i] == '!' && ctx.i+1<ctx.size && is_in(ctx[ctx.i+1], 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)
{
auto pp=parse_block(ctx);
ret->add(pp.first);
ctx = pp.second;
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);
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
// separated by && or ||
// 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);
bool optype=AND_OP;
@ -952,7 +988,7 @@ std::pair<condlist*, parse_context> parse_condlist(parse_context ctx)
auto pp=parse_pipeline(ctx);
ret->add(pp.first, optype);
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);
}
@ -994,9 +1030,9 @@ std::pair<condlist*, parse_context> parse_condlist(parse_context 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);
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)
{
uint8_t do_twice=2;
// case of : cat << EOF ;
while(do_twice>0)
bool has_parsed=false;
parse_context t_ctx=ctx;
if(t_ctx[t_ctx.i] == '\n')
{
if(ctx[ctx.i] == '\n')
{
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--;
t_ctx = parse_heredocument(t_ctx+1);
has_parsed=true;
}
// case of : cat << EOF ; ;
if(do_twice==0 && is_in(ctx[ctx.i], COMMAND_SEPARATOR))
parse_error( unexpected_token(ctx[ctx.i]), ctx);
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;
}
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))
@ -1116,9 +1160,9 @@ std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx
// parse a subshell
// must start right after the opening (
// 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;
ctx.i = skip_unread(ctx);
@ -1138,9 +1182,9 @@ std::pair<subshell*, parse_context> parse_subshell(parse_context ctx)
// parse a brace block
// must start right after the opening {
// 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;
ctx.i = skip_unread(ctx);
@ -1160,9 +1204,9 @@ std::pair<brace*, parse_context> parse_brace(parse_context ctx)
// parse a function
// must start right after the ()
// 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);
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_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_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") )
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)
ret=&in->cmd_var_assigns;
@ -1233,7 +1277,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
else
ctx.i++;
arg* ta=nullptr;
arg_t* ta=nullptr;
if(ctx[ctx.i] == '(') // bash var=()
{
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);
}
ctx.i++;
auto pp=parse_arg(ctx, ")", ARG_OPTIMIZE_DEFARR);
auto pp=parse_arg(ctx, ")", "", false, ARG_OPTIMIZE_DEFARR);
ta=pp.first;
ta->insert(0,"(");
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
{
ta = new arg;
ta = new arg_t;
}
else
{
@ -1263,6 +1307,7 @@ parse_context parse_cmd_varassigns(cmd* in, parse_context ctx, bool cmdassign=fa
ctx=pp.second;
}
ta->insert(0, strop);
ta->forcequoted = !cmdassign;
ret->push_back(std::make_pair(vp.first, ta));
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
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);
@ -1311,8 +1356,8 @@ std::pair<cmd*, parse_context> parse_cmd(parse_context ctx)
parse_error("bash specific: "+wp.first, ctx);
}
ret->args = new arglist;
ret->args->add(new arg(wp.first));
ret->args = new arglist_t;
ret->args->add(new arg_t(wp.first));
ret->is_cmdvar=true;
ctx.i = wp.second;
ctx.i = skip_chars(ctx, SPACES);
@ -1337,9 +1382,9 @@ std::pair<cmd*, parse_context> parse_cmd(parse_context ctx)
// parse a case block
// must start right after the case
// 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);
// 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) )
{
// 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
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);
}
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)
{
@ -1486,9 +1531,9 @@ std::pair<if_block*, parse_context> parse_if(parse_context 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);
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 );
}
ret->var = new variable(wp.first, nullptr, true);
ret->var = new variable_t(wp.first, nullptr, true);
ctx.i = wp.second;
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);
}
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
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
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);
block* ret = nullptr;
block_t* ret = nullptr;
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);
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)
{
delete pp.first;

View file

@ -155,7 +155,7 @@ std::string get_varname(std::string const& 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)
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);
}
bool cmd::is_argvar()
bool cmd_t::is_argvar()
{
return is_cmdvar;
}
bool cmd::is(std::string const& in)
bool cmd_t::is(std::string const& in)
{
return in == this->arg_string(0);
}
@ -285,14 +285,14 @@ void add_unset_variables(shmain* sh, std::regex const& exclude)
varmap_get(sh, exclude);
if(m_vars.size()>0)
{
cmd* unset_cmd = new cmd;
unset_cmd->add(new arg("unset"));
cmd_t* unset_cmd = new cmd_t;
unset_cmd->add(new arg_t("unset"));
unset_cmd->is_cmdvar=true;
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);
}
}
@ -315,7 +315,7 @@ bool r_has_env_set(_obj* in, bool* result)
return false;
}; break;
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")
*result = true;
}
@ -330,8 +330,8 @@ bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
{
switch(in->type)
{
case _obj::_variable: {
variable* t = dynamic_cast<variable*>(in);
case _obj::variable: {
variable_t* t = dynamic_cast<variable_t*>(in);
if(t->definition)
{
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)
{
case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in);
cmd_t* t = dynamic_cast<cmd_t*>(in);
if(t->is("unset"))
{
for(auto it: t->cmd_var_assigns)
@ -373,7 +373,7 @@ bool r_get_cmd(_obj* in, countmap_t* all_cmds)
switch(in->type)
{
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);
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++;
@ -388,7 +388,7 @@ bool r_get_fct(_obj* in, countmap_t* fct_map)
switch(in->type)
{
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)
(*fct_map)[t->name]++;
}; break;
@ -418,14 +418,14 @@ bool r_delete_fct(_obj* in, set_t* fcts)
{
switch(in->type)
{
case _obj::_list: {
list* t = dynamic_cast<list*>(in);
case _obj::list: {
list_t* t = dynamic_cast<list_t*>(in);
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)
{
function* fc = dynamic_cast<function*>(tb);
function_t* fc = dynamic_cast<function_t*>(tb);
if(fcts->find(fc->name)!=fcts->end())
{
delete t->cls[i];
@ -444,16 +444,16 @@ bool r_delete_var(_obj* in, set_t* vars)
{
switch(in->type)
{
case _obj::_list: {
list* t = dynamic_cast<list*>(in);
case _obj::list: {
list_t* t = dynamic_cast<list_t*>(in);
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 has_deleted=false;
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++)
{
@ -549,7 +549,7 @@ bool r_do_string_processor(_obj* in)
{
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);
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;
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("varname"), quote_string(t->varname)));
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) ) );
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("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("here_document"), gen_json_struc(t->here_document)));
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("forcequoted"), boolstring(t->forcequoted)));
std::vector<std::string> tvec;
for(auto it: t->sa)
tvec.push_back(gen_json_struc(it));
vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec)));
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") ) );
std::vector<std::string> tvec;
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)));
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("negated"), boolstring(t->negated) ) );
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)));
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("parallel"), boolstring(t->parallel) ) );
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)));
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") ) );
std::vector<std::string> tvec;
for(auto it: t->cls)
@ -716,7 +717,7 @@ std::string gen_json_struc(_obj* o)
}
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("lst"), gen_json_struc(t->lst)));
@ -730,7 +731,7 @@ std::string gen_json_struc(_obj* o)
}
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("lst"), gen_json_struc(t->lst)));
@ -759,7 +760,7 @@ std::string gen_json_struc(_obj* o)
}
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("name"), quote_string(t->name) ) );
@ -774,7 +775,7 @@ std::string gen_json_struc(_obj* o)
}
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("args"), gen_json_struc(t->args)));
@ -808,7 +809,7 @@ std::string gen_json_struc(_obj* o)
}
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("carg"), gen_json_struc(t->carg)));
@ -837,7 +838,7 @@ std::string gen_json_struc(_obj* o)
}
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") ) );
std::vector<std::string> condblocks;
@ -862,7 +863,7 @@ std::string gen_json_struc(_obj* o)
}
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("var"), gen_json_struc(t->var)));
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 :
{
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("cond"), gen_json_struc(t->cond) ) );
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 :
{
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("var"), gen_json_struc(t->var) ) );
break;
}
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("sbsh"), gen_json_struc(t->sbsh) ) );
break;
}
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("is_output"), boolstring(t->is_output) ) );
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 :
{
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("arith"), gen_json_struc(t->arith) ) );
break;
}
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("val"), quote_string(t->val) ) );
break;
}
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("var"), gen_json_struc(t->var) ) );
break;
}
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("sbsh"), gen_json_struc(t->sbsh) ) );
break;
}
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("val1"), gen_json_struc(t->val1) ) );
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 :
{
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("val"), gen_json_struc(t->val) ) );
break;
}
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("val"), quote_string(t->val) ) );
break;

View file

@ -59,7 +59,7 @@ void _cd(std::string const& dir)
// -- COMMANDS --
// 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;
@ -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;
@ -152,9 +152,9 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, parse_context
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;
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
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;
try
@ -220,11 +220,11 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, parse_context ctx)
// -- 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)
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);
@ -233,17 +233,17 @@ std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, parse_
else if(g_resolve && strcmd == "%resolve")
return std::make_pair(do_resolve_parse(in, ctx), true);
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)
{
return std::make_pair(ret, false);
}
arg* ta=nullptr;
arg_t* ta=nullptr;
bool has_resolved=false;
uint32_t j=0;
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
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
continue;
condlist* tc = tsh->sbsh->lst->cls[0];
cmd* c = tc->first_cmd();
condlist_t* tc = tsh->sbsh->lst->cls[0];
cmd_t* c = tc->first_cmd();
if(c == nullptr) // skip if not cmd
continue;
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
delete in->sa[i];
in->sa[i] = new string_subarg(fulltext);
in->sa[i] = new subarg_string_t(fulltext);
}
else
{
@ -305,21 +305,21 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bo
if(strargs.size() == 1)
val = strargs[0];
delete in->sa[i];
in->sa[i] = new string_subarg(val);
in->sa[i] = new subarg_string_t(val);
}
else // pack
{
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->add(new string_subarg(strargs[i]));
ta->add(new subarg_string_t(strargs[i]));
j=i+1;
delete in->sa[i];
for(uint32_t li=1 ; li<strargs.size() ; li++)
{
ret.push_back(ta);
ta = new arg;
ta->add(new string_subarg(strargs[li]));
ta = new arg_t;
ta->add(new subarg_string_t(strargs[li]));
}
} // end pack
@ -350,9 +350,9 @@ bool r_resolve(_obj* o, parse_context* ct)
// check every sub-object
// execute resolve manually
// 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++)
{
auto r=resolve_condlist(t->cls[i], *ct);
@ -373,9 +373,9 @@ bool r_resolve(_obj* o, parse_context* ct)
}
return false;
} 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++)
{
auto r=resolve_arg(t->args[i], *ct);
@ -397,7 +397,7 @@ bool r_resolve(_obj* o, parse_context* ct)
} break;
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
{
resolve_arg(it.second, *ct, true); // force quoted
@ -415,7 +415,7 @@ bool r_resolve(_obj* o, parse_context* ct)
}; break;
case _obj::block_case :
{
auto t = dynamic_cast<case_block*>(o);
auto t = dynamic_cast<case_t*>(o);
for(auto sc: t->cases)
{
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 = {
{ "_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_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>
std::string g_origin="";
const std::string cmd_t::empty_string="";
const std::string cmd::empty_string="";
condlist::condlist(block* bl)
condlist_t::condlist_t(block_t* bl)
{
type=_obj::_condlist;
type=_obj::condlist;
parallel=false;
this->add(new pipeline(bl));
this->add(new pipeline_t(bl));
}

View file

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