Compare commits

..

No commits in common. "master" and "v1.2.0" have entirely different histories.

56 changed files with 1015 additions and 3213 deletions

6
.gitignore vendored
View file

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

View file

@ -87,10 +87,3 @@ clean:
clear: clear:
rm $(BINDIR)/$(NAME) rm $(BINDIR)/$(NAME)
install:
cp lxsh /usr/local/bin
cp completion/lxsh.bash /etc/bash_completion.d
uninstall:
rm /usr/local/bin/lxsh /etc/bash_completion.d/lxsh.bash

View file

@ -14,14 +14,14 @@ wget -qO- https://zpkg.zawz.net/install.sh | sh
zpkg install lxsh zpkg install lxsh
``` ```
### Binary amd64 ### Binary
Download the `lxsh-linux-amd64.tar.gz` archive, extract it, Download the `lxsh.tar.gz` archive, extract it,
and move the `lxsh` binary in a PATH folder (`/usr/local/bin` is the recommended). and move the `lxsh` binary in a PATH folder (`/usr/local/bin` is the recommended).
```shell ```shell
wget https://github.com/zawwz/lxsh/releases/download/v1.3.0/lxsh-linux-amd64.tar.gz wget https://github.com/zawwz/lxsh/releases/download/v1.2.0/lxsh-linux-amd64.tar.gz
tar -xvf lxsh-linux-amd64.tar.gz tar -xvf lxsh.tar.gz
sudo mv lxsh /usr/local/bin sudo mv lxsh /usr/local/bin
``` ```
@ -45,22 +45,6 @@ These commands can be placed anywhere within the script like regular commands.
Reduce code size to a minimum without changing functionality with the `-m` option. Reduce code size to a minimum without changing functionality with the `-m` option.
> This option should be safe to use in any situation, if this option changes behavior please report a bug
#### Behaviors of the minify option
- removes any unnecessary separator character between arguments/commands
- 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
- 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
could expand the variable name
### Further minifying ### Further minifying
The script can be further minified by altering code elements. The script can be further minified by altering code elements.
@ -72,6 +56,8 @@ use `--exclude-var` to exclude variables from being minified (for example enviro
Function names can be minified with `--minify-fct`, Function names can be minified with `--minify-fct`,
use `--exclude-fct` to exclude functions from being minified. use `--exclude-fct` to exclude functions from being minified.
Unnecessary quotes can be removed with `--minify-quotes`.
Unused functions and variables can be removed with `--remove-unused`. Unused functions and variables can be removed with `--remove-unused`.
Use `-M` to enable all of these minifying features (you still have to specify `--exclude` options when needed) Use `-M` to enable all of these minifying features (you still have to specify `--exclude` options when needed)
@ -87,9 +73,6 @@ The following bash features can be debashified:
- `[[ ]]` conditions - `[[ ]]` conditions
- indexed arrays and associative arrays (+ their `declare` and `typeset` definitions) - indexed arrays and associative arrays (+ their `declare` and `typeset` definitions)
- `$RANDOM` - `$RANDOM`
- substring variable manipulation (`${VAR:N:M}`)
- variable substitution (`${!VAR}`)
- search replace manipulation (`${VAR/s/a/b}` )
### Advantages ### Advantages
@ -139,10 +122,6 @@ these features will continue working with undesired behavior.
Array argument with `[@]` does not expand into the desired multiple arguments. Array argument with `[@]` does not expand into the desired multiple arguments.
#### Substring manipulation
Debashifying a substring manipulation on a variable containing a newline will not work correctly
## Extension commands ## Extension commands
If you use the `#!/usr/bin/lxsh` shebang, you can use special lxsh-defined commands. If you use the `#!/usr/bin/lxsh` shebang, you can use special lxsh-defined commands.
@ -178,6 +157,8 @@ Directly execute an extended lxsh script with either
> Direct execution introduces direct dependency on lxsh and code parsing overhead, > Direct execution introduces direct dependency on lxsh and code parsing overhead,
> therefore it should be avoided in production environments. > therefore it should be avoided in production environments.
> stdin is known to not work properly on direct execution as of now
### Variable/Function/command listing ### Variable/Function/command listing
You can list all calls of variables, functions or commands with `--list-*` options You can list all calls of variables, functions or commands with `--list-*` options

View file

@ -1,3 +0,0 @@
#/usr/bin/env bash
complete -F _longopt lxsh

View file

@ -2,22 +2,17 @@
#define MINIFY_HPP #define MINIFY_HPP
#include "struc.hpp" #include "struc.hpp"
#include "processing.hpp"
#include <regex> #include <regex>
#include <string> #include <string>
std::string gen_minmap(strmap_t const& map, std::string const& prefix); void minify_var(_obj* in, std::regex const& exclude);
void read_minmap(std::string const& filepath, strmap_t* varmap, strmap_t* fctmap); void minify_fct(_obj* in, std::regex const& exclude);
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);
bool delete_unused_fct(_obj* in, std::regex const& exclude);
bool delete_unused_var(_obj* in, std::regex const& exclude);
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude); void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude);
void minify_generic(_obj* in); void minify_quotes(_obj* in);
#endif //MINIFY_HPP #endif //MINIFY_HPP

View file

@ -6,12 +6,11 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <set>
#include <tuple> #include <tuple>
#define SPACES " \t" #define SPACES " \t"
#define SEPARATORS " \t\n" #define SEPARATORS " \t\n"
#define ARG_END " \t\n;()&|<>" #define ARG_END " \t\n;#()&|<>"
#define VARNAME_END " \t\n;#()&|=\"'\\{}/-+" #define VARNAME_END " \t\n;#()&|=\"'\\{}/-+"
#define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\" #define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\"
#define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}" #define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}"
@ -19,22 +18,19 @@
#define CONTROL_END "#)" #define CONTROL_END "#)"
#define PIPELINE_END "\n;#()&" #define PIPELINE_END "\n;#()&"
#define ARGLIST_END "\n;#()&|" #define ARGLIST_END "\n;#()&|"
#define SPECIAL_TOKENS "\n;#()&|"
#define ALL_TOKENS "\n;#()&|{}" #define ALL_TOKENS "\n;#()&|{}"
#define ARITHMETIC_OPERATOR_END " \t\n$)"
#define SPECIAL_VARS "!#*@$?" #define SPECIAL_VARS "!#*@$?"
// bash specific // bash specific
#define ARRAY_ARG_END " \t\n;#()&|<>]" #define ARRAY_ARG_END " \t\n;#()&|<>]"
// optimizations
#define ARG_OPTIMIZE_NULL "$\\`" // macros
#define ARG_OPTIMIZE_MANIP "$\\`}" // #define PARSE_ERROR_I(str, ctx, i) format_error(str, ctx.filename, ctx.data, i)
#define ARG_OPTIMIZE_DEFARR "$\\`)" // #define PARSE_ERROR(str, ctx) format_error(str, ctx.filename, ctx.data, ctx.i)
#define ARG_OPTIMIZE_BASHTEST "$\\`] \t\n" // #define PARSE_ERROR_I(str, ctx, i) { printFormatError(format_error(str, ctx.filename, ctx.data, i)); ctx.has_errored=true; }
#define ARG_OPTIMIZE_ARG "$\\` \t\n;()&|<>\"'" // #define PARSE_ERROR(str, ctx) { printFormatError(format_error(str, ctx.filename, ctx.data, ctx.i)); ctx.has_errored=true; }
#define ARG_OPTIMIZE_ARRAY "$\\`\t\n&|}[]\"'"
#define ARG_OPTIMIZE_ALL "$\\` \t\n;#()&|<>}]\"'"
// structs // structs
@ -46,9 +42,9 @@ struct list_parse_options {
}; };
// globals // globals
extern const std::set<std::string> all_reserved_words;
extern const std::set<std::string> posix_cmdvar; extern const std::vector<std::string> posix_cmdvar;
extern const std::set<std::string> bash_cmdvar; extern const std::vector<std::string> bash_cmdvar;
std::string import_file(std::string const& path); std::string import_file(std::string const& path);
@ -88,41 +84,37 @@ uint32_t skip_unread(const char* in, uint32_t size, uint32_t start);
inline uint32_t skip_unread(parse_context const& ct) { inline uint32_t skip_unread(parse_context const& ct) {
return skip_unread(ct.data, ct.size, ct.i); return skip_unread(ct.data, ct.size, ct.i);
} }
uint32_t skip_unread_noline(const char* in, uint32_t size, uint32_t start);
inline uint32_t skip_unread_noline(parse_context const& ct) {
return skip_unread_noline(ct.data, ct.size, ct.i);
}
// heredocument
parse_context parse_heredocument(parse_context ctx);
// list // list
std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={}); // std::pair<list*, parse_context> parse_list_until(parse_context ct, 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={});
// name // name
std::pair<variable_t*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false); std::pair<variable*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
// subarg parsers // subarg parsers
std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ct); std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ct);
std::pair<variable_t*, parse_context> parse_manipulation(parse_context ct); std::pair<variable*, parse_context> parse_manipulation(parse_context ct);
// arg parser // arg parser
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); std::pair<arg*, parse_context> parse_arg(parse_context ct, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true);
// redirect parser // redirect parser
std::pair<redirect_t*, parse_context> parse_redirect(parse_context ct); std::pair<redirect*, parse_context> parse_redirect(parse_context ct);
// arglist parser // arglist parser
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); std::pair<arglist*, parse_context> parse_arglist(parse_context ct, bool hard_error=false, std::vector<redirect*>* redirs=nullptr);
// block parsers // block parsers
std::pair<block_t*, parse_context> parse_block(parse_context ct); std::pair<block*, parse_context> parse_block(parse_context ct);
std::pair<cmd_t*, parse_context> parse_cmd(parse_context ct); std::pair<cmd*, parse_context> parse_cmd(parse_context ct);
std::pair<function_t*, parse_context> parse_function(parse_context ct, const char* after="()"); std::pair<function*, parse_context> parse_function(parse_context ct, const char* after="()");
std::pair<subshell_t*, parse_context> parse_subshell(parse_context ct); std::pair<subshell*, parse_context> parse_subshell(parse_context ct);
std::pair<brace_t*, parse_context> parse_brace(parse_context ct); std::pair<brace*, parse_context> parse_brace(parse_context ct);
std::pair<case_t*, parse_context> parse_case(parse_context ct); std::pair<case_block*, parse_context> parse_case(parse_context ct);
std::pair<if_t*, parse_context> parse_if(parse_context ct); std::pair<if_block*, parse_context> parse_if(parse_context ct);
std::pair<for_t*, parse_context> parse_for(parse_context ct); std::pair<for_block*, parse_context> parse_for(parse_context ct);
std::pair<while_t*, parse_context> parse_while(parse_context ct); std::pair<while_block*, parse_context> parse_while(parse_context ct);
// pipeline parser // pipeline parser
std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ct); std::pair<pipeline*, parse_context> parse_pipeline(parse_context ct);
// condlist parser // condlist parser
std::pair<condlist_t*, parse_context> parse_condlist(parse_context ct); std::pair<condlist*, parse_context> parse_condlist(parse_context ct);
#endif //PARSE_HPP #endif //PARSE_HPP

View file

@ -9,7 +9,7 @@
#include "struc.hpp" #include "struc.hpp"
// constants // constants
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR", "IFS" #define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR"
// types // types
typedef std::map<std::string,uint32_t> countmap_t; typedef std::map<std::string,uint32_t> countmap_t;
@ -29,12 +29,9 @@ extern set_t m_excluded_var, m_excluded_fct, m_excluded_cmd;
extern bool b_gotvar, b_gotfct, b_gotcmd; extern bool b_gotvar, b_gotfct, b_gotcmd;
// tools
countmap_t combine_maps(countmap_t const& a, countmap_t const& b);
countmap_t combine_common(countmap_t const& a, countmap_t const& b);
/** map get functions (optimizations) **/ /** map get functions (optimizations) **/
// rescans // rescans
void require_rescan_all(); void require_rescan_all();
void require_rescan_var(); void require_rescan_var();
@ -45,13 +42,9 @@ void require_rescan_cmd();
void varmap_get(_obj* in, std::regex const& exclude); void varmap_get(_obj* in, std::regex const& exclude);
void fctmap_get(_obj* in, std::regex const& exclude); void fctmap_get(_obj* in, std::regex const& exclude);
void cmdmap_get(_obj* in, std::regex const& exclude); void cmdmap_get(_obj* in, std::regex const& exclude);
void fctcmdmap_get(_obj* in, std::regex const& exclude_fct, std::regex const& exclude_cmd);
void allmaps_get(_obj* in, std::regex const& exclude_var, std::regex const& exclude_fct, std::regex const& exclude_cmd);
/** util functions **/ /** util functions **/
#ifdef DEBUG_MODE
std::string gen_json_struc(_obj* in); std::string gen_json_struc(_obj* in);
#endif
// gen regexes // gen regexes
std::regex var_exclude_regex(std::string const& in, bool include_reserved); std::regex var_exclude_regex(std::string const& in, bool include_reserved);
@ -60,7 +53,7 @@ std::regex fct_exclude_regex(std::string const& in);
// varnames // varnames
bool is_varname(std::string const& in); bool is_varname(std::string const& in);
std::string get_varname(std::string const& in); std::string get_varname(std::string const& in);
std::string get_varname(arg_t* in); std::string get_varname(arg* in);
// list objects // list objects
void list_map(countmap_t const& map); void list_map(countmap_t const& map);
@ -71,23 +64,17 @@ void list_fcts(_obj* in, std::regex const& exclude);
void list_cmds(_obj* in, std::regex const& exclude); void list_cmds(_obj* in, std::regex const& exclude);
// recursives // recursives
bool r_has_env_set(_obj* in, bool* result);
bool r_get_unsets(_obj* in, set_t* unsets); bool r_get_unsets(_obj* in, set_t* unsets);
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap); bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap);
bool r_get_cmd(_obj* in, countmap_t* all_cmds); bool r_get_cmd(_obj* in, countmap_t* all_cmds);
bool r_get_fct(_obj* in, countmap_t* fct_map); bool r_get_fct(_obj* in, countmap_t* fct_map);
bool r_get_fctcmd(_obj* in, countmap_t* all_cmds, countmap_t* fct_map);
bool r_get_all(_obj* in, countmap_t* defmap, countmap_t* callmap, countmap_t* all_cmds, countmap_t* fct_map);
bool r_delete_fct(_obj* in, set_t* fcts); bool r_delete_fct(_obj* in, set_t* fcts);
bool r_delete_var(_obj* in, set_t* vars); bool r_delete_var(_obj* in, set_t* vars);
bool r_delete_varfct(_obj* in, set_t* vars, set_t* fcts);
bool r_do_string_processor(_obj* in);
/** Processing **/ /** Processing **/
std::set<std::string> find_lxsh_commands(shmain* sh); std::set<std::string> find_lxsh_commands(shmain* sh);
void add_unset_variables(shmain* sh, std::regex const& exclude); void add_unset_variables(shmain* sh, std::regex const& exclude);
bool has_env_set(_obj* in);
void string_processors(_obj* in); void string_processors(_obj* in);

View file

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

View file

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

View file

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

View file

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

View file

@ -24,6 +24,8 @@ inline bool is_dev_file(std::string const& filename) { return filename.substr(0,
std::string indent(int n); std::string indent(int n);
bool is_among(std::string const& in, std::vector<std::string> const& values);
std::vector<std::string> split(std::string const& in, const char* splitters); std::vector<std::string> split(std::string const& in, const char* splitters);
std::vector<std::string> split(std::string const& in, char c); std::vector<std::string> split(std::string const& in, char c);
@ -126,17 +128,6 @@ void concat_sets(std::set<T>& a, std::set<T> const& b)
} }
} }
template <class T>
void exclude_sets(std::set<T>& a, std::set<T> const& b)
{
for(auto it: b)
{
auto t = a.find(it);
if(t != a.end())
a.erase(t);
}
}
template <class T> template <class T>
bool is_in_vector(T el, std::vector<T> vec) bool is_in_vector(T el, std::vector<T> vec)
{ {
@ -146,12 +137,6 @@ bool is_in_vector(T el, std::vector<T> vec)
return false; return false;
} }
template <class T>
bool is_in_set(T el, std::set<T> ss)
{
return ss.find(el) != ss.end();
}
std::set<std::string> prune_matching(std::set<std::string>& in, std::regex re); std::set<std::string> prune_matching(std::set<std::string>& in, std::regex re);
std::string delete_brackets(std::string const& in); std::string delete_brackets(std::string const& in);
@ -161,7 +146,6 @@ std::string concatargs(std::vector<std::string> const& args);
int _exec(std::string const& bin, std::vector<std::string> const& args); int _exec(std::string const& bin, std::vector<std::string> const& args);
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace); std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);
std::string escape_chars(std::string subject, const char* chars);
void printFormatError(format_error const& e, bool print_line=true); void printFormatError(format_error const& e, bool print_line=true);

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,9 @@
#define PIPE_READ 0 #define PIPE_READ 0
#define PIPE_WRITE 1 #define PIPE_WRITE 1
std::vector<condlist_t*> do_include_exec(condlist_t* cmd, parse_context ctx, FILE* fd) std::vector<condlist*> do_include_exec(condlist* cmd, parse_context ctx, FILE* fd)
{ {
std::vector<condlist_t*> ret; std::vector<condlist*> ret;
std::string dir; std::string dir;
auto incs=do_include_raw(cmd, ctx, &dir); auto incs=do_include_raw(cmd, ctx, &dir);
@ -36,9 +36,9 @@ std::vector<condlist_t*> do_include_exec(condlist_t* cmd, parse_context ctx, FIL
} }
// if first is nullptr: is a string // if first is nullptr: is a string
std::vector<condlist_t*> do_resolve_exec(condlist_t* cmd, parse_context ctx, FILE* fd) std::vector<condlist*> do_resolve_exec(condlist* cmd, parse_context ctx, FILE* fd)
{ {
std::vector<condlist_t*> ret; std::vector<condlist*> ret;
std::pair<std::string,std::string> p; std::pair<std::string,std::string> p;
try try
@ -61,9 +61,9 @@ std::vector<condlist_t*> do_resolve_exec(condlist_t* cmd, parse_context ctx, FIL
// -- OBJECT CALLS -- // -- OBJECT CALLS --
bool resolve_condlist_exec(condlist_t* in, parse_context ctx, FILE* fd) bool resolve_condlist_exec(condlist* in, parse_context ctx, FILE* fd)
{ {
cmd_t* tc = in->first_cmd(); cmd* tc = in->first_cmd();
if(tc == nullptr) if(tc == nullptr)
return false; return false;
@ -83,7 +83,7 @@ bool resolve_condlist_exec(condlist_t* in, parse_context ctx, FILE* fd)
} }
bool resolve_exec(condlist_t* in, parse_context ctx, FILE* fd) bool resolve_exec(condlist* in, parse_context ctx, FILE* fd)
{ {
if(!resolve_condlist_exec(in, ctx, fd)) if(!resolve_condlist_exec(in, ctx, fd))
{ {
@ -143,7 +143,7 @@ void parse_exec(FILE* fd, parse_context ctx)
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
debashify_params debash_params; debashify_params debash_params;
list_t* t_lst=new list_t; list* t_lst=new list;
if(t_lst == nullptr) if(t_lst == nullptr)
throw std::runtime_error("Alloc error"); throw std::runtime_error("Alloc error");
while(ctx.i<ctx.size) while(ctx.i<ctx.size)
@ -194,12 +194,15 @@ void parse_exec(FILE* fd, parse_context ctx)
pid_t forkexec(const char* bin, char *const args[]) pid_t forkexec(const char* bin, char *const args[])
{ {
pid_t child_pid; pid_t child_pid;
// int tfd = dup(STDIN_FILENO);
// std::cout << tfd << std::endl;
if((child_pid = vfork()) == -1) if((child_pid = vfork()) == -1)
{ {
throw std::runtime_error("fork() failed"); throw std::runtime_error("fork() failed");
} }
if (child_pid == 0) // child process if (child_pid == 0) // child process
{ {
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execv(bin, args); execv(bin, args);
throw std::runtime_error("execv() failed"); throw std::runtime_error("execv() failed");
} }
@ -236,11 +239,6 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
if(mkfifo(fifopath.c_str(), 0700)<0) if(mkfifo(fifopath.c_str(), 0700)<0)
throw std::runtime_error("Cannot create fifo "+fifopath); throw std::runtime_error("Cannot create fifo "+fifopath);
pid_t pid=0;
FILE* ffd=0;
try
{
for(uint32_t i=0; i<strargs.size(); i++) for(uint32_t i=0; i<strargs.size(); i++)
runargs.push_back((char*) strargs[i].c_str()); runargs.push_back((char*) strargs[i].c_str());
runargs.push_back((char*) fifopath.c_str()); runargs.push_back((char*) fifopath.c_str());
@ -248,6 +246,10 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
runargs.push_back((char*) args[i].c_str()); runargs.push_back((char*) args[i].c_str());
runargs.push_back(NULL); runargs.push_back(NULL);
pid_t pid=0;
FILE* ffd=0;
try
{
pid = forkexec(runargs[0], runargs.data()); pid = forkexec(runargs[0], runargs.data());
ffd = fopen(fifopath.c_str(), "w"); ffd = fopen(fifopath.c_str(), "w");
if(options["debashify"]) if(options["debashify"])
@ -261,10 +263,10 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
} }
catch(std::runtime_error& e) catch(std::runtime_error& e)
{ {
if(pid != 0)
kill(pid, SIGINT);
fclose(ffd); fclose(ffd);
unlink(fifopath.c_str()); unlink(fifopath.c_str());
if(pid != 0)
kill(pid, SIGINT);
throw e; throw e;
} }

View file

@ -6,9 +6,6 @@
#include "options.hpp" #include "options.hpp"
#include "parse.hpp" #include "parse.hpp"
// global
bool prev_is_heredoc=false;
bool is_sub_special_cmd(std::string in) bool is_sub_special_cmd(std::string in)
{ {
return in == "%include_sub" || in == "%resolve_sub"; return in == "%include_sub" || in == "%resolve_sub";
@ -22,7 +19,7 @@ std::string indented(std::string const& in, uint32_t ind)
return in; return in;
} }
std::string arg_t::generate(int ind) std::string arg::generate(int ind)
{ {
std::string ret; std::string ret;
for(auto it: sa) for(auto it: sa)
@ -32,7 +29,7 @@ std::string arg_t::generate(int ind)
return ret; return ret;
} }
std::string arglist_t::generate(int ind) std::string arglist::generate(int ind)
{ {
std::string ret; std::string ret;
@ -47,7 +44,7 @@ std::string arglist_t::generate(int ind)
return ret; return ret;
} }
std::string pipeline_t::generate(int ind, generate_context* ctx) std::string pipeline::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -56,10 +53,6 @@ std::string pipeline_t::generate(int ind, generate_context* ctx)
if(negated) if(negated)
ret += "! "; ret += "! ";
if(bash_time)
ret += "time ";
ret += cmds[0]->generate(ind, ctx); ret += cmds[0]->generate(ind, ctx);
for(uint32_t i=1 ; i<cmds.size() ; i++) for(uint32_t i=1 ; i<cmds.size() ; i++)
{ {
@ -70,7 +63,7 @@ std::string pipeline_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string condlist_t::generate(int ind) std::string condlist::generate(int ind)
{ {
std::string ret; std::string ret;
if(pls.size() <= 0) if(pls.size() <= 0)
@ -85,7 +78,6 @@ std::string condlist_t::generate(int ind)
ret += opt_minify ? "&&" : " && "; ret += opt_minify ? "&&" : " && ";
ret += pls[i+1]->generate(ind, &ctx); ret += pls[i+1]->generate(ind, &ctx);
} }
prev_is_heredoc=false;
if(ret=="") if(ret=="")
return ""; return "";
if(ctx.here_document != nullptr) if(ctx.here_document != nullptr)
@ -95,7 +87,6 @@ std::string condlist_t::generate(int ind)
ret += '\n'; ret += '\n';
ret += ctx.here_document->generate(0); ret += ctx.here_document->generate(0);
ret += '\n'; ret += '\n';
prev_is_heredoc=true;
} }
else if(parallel) else if(parallel)
{ {
@ -106,47 +97,42 @@ std::string condlist_t::generate(int ind)
return ret; return ret;
} }
std::string list_t::generate(int ind, bool first_indent) std::string list::generate(int ind, bool first_indent)
{ {
std::string ret; std::string ret;
if(cls.size() <= 0) if(cls.size() <= 0)
return ""; return "";
std::string next;
for(uint32_t i=0; i<cls.size(); i++) for(uint32_t i=0; i<cls.size(); i++)
{ {
if(first_indent) if(first_indent)
{ {
next = indented(cls[i]->generate(ind), ind); ret += indented(cls[i]->generate(ind), ind);
} }
else else
{ {
first_indent=true; first_indent=true;
next = cls[i]->generate(ind); ret += cls[i]->generate(ind);
} }
if(ret[ret.size()-1] == '&' && next.size()>0 && is_in(next[0], "<>"))
ret += '\n';
ret += next;
} }
return ret; return ret;
} }
std::string redirect_t::generate(int ind) std::string redirect::generate(int ind)
{ {
std::string ret=op; std::string ret=op;
if(target!=nullptr) if(target!=nullptr)
{ {
std::string targetret=target->generate(0); if(!opt_minify)
if(!(opt_minify && !is_in(targetret[0], "<>")))
ret += ' '; ret += ' ';
ret += targetret; ret += target->generate(0);
} }
return ret; return ret;
} }
// BLOCK // BLOCK
std::string block_t::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr) std::string block::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr)
{ {
std::string ret=" "; std::string ret=" ";
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]); bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
@ -168,7 +154,7 @@ std::string block_t::generate_redirs(int ind, std::string const& _str, generate_
return ret; return ret;
} }
std::string if_t::generate(int ind, generate_context* ctx) std::string if_block::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -202,16 +188,13 @@ std::string if_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string for_t::generate(int ind, generate_context* ctx) std::string for_block::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
ret += "for "+var->generate(ind); ret += "for "+var->generate(ind);
if(in_val) {
ret += " in";
if(iter != nullptr) if(iter != nullptr)
ret += " " + iter->generate(ind); ret += " in " + iter->generate(ind);
}
ret += '\n'; ret += '\n';
ret += indented("do\n", ind); ret += indented("do\n", ind);
ret += ops->generate(ind+1); ret += ops->generate(ind+1);
@ -223,7 +206,7 @@ std::string for_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string while_t::generate(int ind, generate_context* ctx) std::string while_block::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -243,7 +226,7 @@ std::string while_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string subshell_t::generate(int ind, generate_context* ctx) std::string subshell::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
// open subshell // open subshell
@ -276,7 +259,7 @@ std::string shmain::generate(bool print_shebang, int ind)
return ret; return ret;
} }
std::string brace_t::generate(int ind, generate_context* ctx) std::string brace::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
@ -288,7 +271,7 @@ std::string brace_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string function_t::generate(int ind, generate_context* ctx) std::string function::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
// function definition // function definition
@ -303,7 +286,7 @@ std::string function_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string case_t::generate(int ind, generate_context* ctx) std::string case_block::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
ret += "case " + carg->generate(ind) + " in\n"; ret += "case " + carg->generate(ind) + " in\n";
@ -321,19 +304,17 @@ std::string case_t::generate(int ind, generate_context* ctx)
// commands // commands
ret += cs.second->generate(ind+1); ret += cs.second->generate(ind+1);
// end of case: ;; // end of case: ;;
if(opt_minify && !prev_is_heredoc && ret[ret.size()-1] == '\n') // ;; can be right after command if(opt_minify && ret[ret.size()-1] == '\n') // ;; can be right after command
ret.pop_back(); ret.pop_back();
ret += indented(";;", ind+1); ret += indented(";;", ind+1);
if(!opt_minify) if(!opt_minify)
ret+="\n"; ret+="\n";
} }
// replace ;; from last case with \n // replace ;; from last case with ;
if(this->cases.size()>0 && opt_minify) if(this->cases.size()>0 && opt_minify)
{ {
ret.pop_back(); ret.pop_back();
ret.pop_back();
ret+='\n';
} }
// close case // close case
@ -344,28 +325,15 @@ std::string case_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
std::string cmd_t::generate(int ind, generate_context* ctx) std::string cmd::generate(int ind, generate_context* ctx)
{ {
std::string ret; std::string ret;
bool has_args=false;
// pre-cmd var assigns
for(auto it: var_assigns)
{
has_args=true;
if(it.first != nullptr)
ret += it.first->generate(ind);
if(it.second != nullptr)
ret += it.second->generate(ind);
ret += ' ';
}
// is a varassign cmd // is a varassign cmd
if(is_cmdvar) if(is_cmdvar)
{ {
ret += args->generate(ind) + ' '; ret += args->generate(ind) + ' ';
for(auto it: cmd_var_assigns) for(auto it: var_assigns)
{ {
if(it.first != nullptr) if(it.first != nullptr)
ret += it.first->generate(ind); ret += it.first->generate(ind);
@ -377,10 +345,19 @@ std::string cmd_t::generate(int ind, generate_context* ctx)
return ret; return ret;
} }
// pre-cmd var assigns
for(auto it: var_assigns)
{
if(it.first != nullptr)
ret += it.first->generate(ind);
if(it.second != nullptr)
ret += it.second->generate(ind);
ret += ' ';
}
// cmd itself // cmd itself
if(args!=nullptr && args->size()>0) if(args!=nullptr && args->size()>0)
{ {
has_args=true;
// command // command
ret += args->generate(ind); ret += args->generate(ind);
// delete potential trailing space // delete potential trailing space
@ -393,28 +370,18 @@ std::string cmd_t::generate(int ind, generate_context* ctx)
ret.pop_back(); ret.pop_back();
} }
std::string redirs = generate_redirs(ind, ret, ctx); ret += generate_redirs(ind, ret, ctx);
if(!has_args)
redirs.erase(redirs.begin());
ret += redirs;
return ret; return ret;
} }
// SUBARG // SUBARG
std::string subarg_subshell_t::generate(int ind) std::string subshell_subarg::generate(int ind)
{ {
std::string r = sbsh->generate(ind); return '$' + sbsh->generate(ind);
if(backtick) {
r[0] = '`';
r[r.size()-1] = '`';
return r;
}
else
return '$' + r;
} }
std::string subarg_procsub_t::generate(int ind) std::string procsub_subarg::generate(int ind)
{ {
if(is_output) if(is_output)
return '>' + sbsh->generate(ind); return '>' + sbsh->generate(ind);
@ -422,7 +389,7 @@ std::string subarg_procsub_t::generate(int ind)
return '<' + sbsh->generate(ind); return '<' + sbsh->generate(ind);
} }
std::string subarg_arithmetic_t::generate(int ind) std::string arithmetic_subarg::generate(int ind)
{ {
std::string ret; std::string ret;
ret += "$(("; ret += "$((";
@ -435,7 +402,7 @@ std::string subarg_arithmetic_t::generate(int ind)
// ARITHMETIC // ARITHMETIC
std::string arithmetic_operation_t::generate(int ind) std::string operation_arithmetic::generate(int ind)
{ {
std::string ret; std::string ret;
if(precedence) if(precedence)
@ -455,7 +422,7 @@ std::string arithmetic_operation_t::generate(int ind)
return ret; return ret;
} }
std::string arithmetic_parenthesis_t::generate(int ind) std::string parenthesis_arithmetic::generate(int ind)
{ {
std::string ret; std::string ret;
ret += '('; ret += '(';
@ -466,12 +433,12 @@ std::string arithmetic_parenthesis_t::generate(int ind)
return ret; return ret;
} }
std::string arithmetic_subshell_t::generate(int ind) std::string subshell_arithmetic::generate(int ind)
{ {
return '$' + sbsh->generate(ind); return '$' + sbsh->generate(ind);
} }
std::string arithmetic_variable_t::generate(int ind) std::string variable_arithmetic::generate(int ind)
{ {
std::string ret=var->generate(ind); std::string ret=var->generate(ind);
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip) if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip)
@ -479,7 +446,7 @@ std::string arithmetic_variable_t::generate(int ind)
return ret; return ret;
} }
std::string variable_t::generate(int ind) std::string variable::generate(int ind)
{ {
std::string ret; std::string ret;
if(is_manip) if(is_manip)

View file

@ -72,7 +72,7 @@ int main(int argc, char* argv[])
// parsing // parsing
sh = new shmain; sh = new shmain(new list);
bool is_exec = false; bool is_exec = false;
bool first_run = true; bool first_run = true;
@ -94,24 +94,9 @@ int main(int argc, char* argv[])
{ {
first_run=false; first_run=false;
// resolve shebang // resolve shebang
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";
}
else
{
binshebang = basename(shebang); binshebang = basename(shebang);
shebang_is_bin = ( basename(argv[0]) == binshebang ); shebang_is_bin = ( basename(argv[0]) == binshebang );
parse_bash = (options["debashify"] || binshebang == "bash" || binshebang == "lxsh"); parse_bash = (options["debashify"] || binshebang == "bash" || binshebang == "lxsh");
}
// detect if need execution // detect if need execution
if(options['e']) if(options['e'])
@ -138,16 +123,16 @@ int main(int argc, char* argv[])
} }
// parse // parse
g_origin=file;
if(!add_include(file)) if(!add_include(file))
continue; continue;
ctx.data=filecontents.data(); ctx.data=filecontents.data();
ctx = make_context(filecontents, file, parse_bash); ctx = make_context(filecontents, file, parse_bash);
if(is_exec) if(is_exec)
{ {
delete sh;
sh = nullptr;
args.erase(args.begin()); args.erase(args.begin());
return exec_process(shebang.substr(2), args, ctx); return exec_process(shebang.substr(2), args, ctx);
} }
@ -155,8 +140,6 @@ int main(int argc, char* argv[])
{ {
auto pp = parse_text(ctx); auto pp = parse_text(ctx);
tsh = pp.first; tsh = pp.first;
if(options["bash"])
tsh->shebang = "#!/usr/bin/env bash";
ctx = pp.second; ctx = pp.second;
if(shebang_is_bin) // resolve lxsh shebang to sh if(shebang_is_bin) // resolve lxsh shebang to sh
tsh->shebang="#!/bin/sh"; tsh->shebang="#!/bin/sh";
@ -188,6 +171,12 @@ int main(int argc, char* argv[])
list_fcts(sh, re_fct_exclude); list_fcts(sh, re_fct_exclude);
else if(options["list-cmd"]) else if(options["list-cmd"])
list_cmds(sh, regex_null); list_cmds(sh, regex_null);
#ifdef DEBUG_MODE
else if(options['J'])
{
std::cout << gen_json_struc(sh) << std::endl;
}
#endif
// output // output
else else
{ {
@ -203,46 +192,21 @@ int main(int argc, char* argv[])
// processing before output // processing before output
// minify // minify
strmap_t varmap, fctmap;
if(options['m']) if(options['m'])
{ {
opt_minify=true; opt_minify=true;
minify_generic(sh); string_processors(sh);
}
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);
varmap = minify_var( sh, re_var_exclude );
fctmap = minify_fct( sh, re_fct_exclude );
}
else if(options["minify-var"]) {
varmap = minify_var( sh, re_var_exclude );
}
else if(options["minify-fct"]) {
fctmap = minify_fct( sh, re_fct_exclude );
} }
if(options["minify-quotes"])
minify_quotes(sh);
if(options["minify-var"])
minify_var( sh, re_var_exclude );
if(options["minify-fct"])
minify_fct( sh, re_fct_exclude );
// other processing // other processing
if(options["unset-var"]) if(options["unset-var"])
add_unset_variables( sh, re_var_exclude ); add_unset_variables( sh, re_var_exclude );
if(options['P']) {
std::ofstream(options['P'].argument) << gen_minmap(varmap, "var") << gen_minmap(fctmap, "fct");
}
#ifdef DEBUG_MODE
if(options['J'])
{
std::cout << gen_json_struc(sh) << std::endl;
}
else
#endif
if(options['o']) // file output if(options['o']) // file output
{ {
std::string destfile=options['o']; std::string destfile=options['o'];
@ -283,6 +247,7 @@ int main(int argc, char* argv[])
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return ERR_RUNTIME; return ERR_RUNTIME;
} }
delete sh; delete sh;
return ret; return ret;

View file

@ -1,15 +1,14 @@
#include "minify.hpp" #include "minify.hpp"
#include <fstream>
#include "parse.hpp" #include "parse.hpp"
#include "recursive.hpp" #include "recursive.hpp"
#include "processing.hpp" #include "processing.hpp"
#include "util.hpp" #include "util.hpp"
std::vector<subarg_t*> cmd_t::subarg_vars() std::vector<subarg*> cmd::subarg_vars()
{ {
std::vector<subarg_t*> ret; std::vector<subarg*> ret;
if(args==nullptr || args->size()<=0) if(args==nullptr || args->size()<=0)
return ret; return ret;
@ -17,7 +16,7 @@ std::vector<subarg_t*> cmd_t::subarg_vars()
{ {
for(uint32_t i=1; i<args->size(); i++) for(uint32_t i=1; i<args->size(); i++)
{ {
arg_t* ta = args->args[i]; arg* ta = args->args[i];
if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string) if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string)
continue; continue;
if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0))) if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0)))
@ -35,19 +34,19 @@ bool r_replace_fct(_obj* in, strmap_t* fctmap)
switch(in->type) switch(in->type)
{ {
case _obj::block_function: { case _obj::block_function: {
function_t* t = dynamic_cast<function_t*>(in); function* t = dynamic_cast<function*>(in);
auto el=fctmap->find(t->name); auto el=fctmap->find(t->name);
if(el!=fctmap->end()) if(el!=fctmap->end())
t->name = el->second; t->name = el->second;
}; break; }; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd_t* t = dynamic_cast<cmd_t*>(in); cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->arg_string(0); std::string cmdname = t->arg_string(0);
auto el=fctmap->find(cmdname); auto el=fctmap->find(cmdname);
if(el!=fctmap->end()) if(el!=fctmap->end())
{ {
delete t->args->args[0]; delete t->args->args[0];
t->args->args[0] = new arg_t(el->second); t->args->args[0] = new arg(el->second);
} }
}; break; }; break;
default: break; default: break;
@ -59,8 +58,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::variable: { case _obj::_variable: {
variable_t* t = dynamic_cast<variable_t*>(in); variable* t = dynamic_cast<variable*>(in);
auto el=varmap->find(t->varname); auto el=varmap->find(t->varname);
if(el!=varmap->end()) if(el!=varmap->end())
t->varname = el->second; t->varname = el->second;
@ -70,20 +69,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
return true; return true;
} }
const char* singlequote_escape_char=" \\\t!\"()|&*?~><#$"; const char* escaped_char=" \\\t!\"()|&*?~><";
const char* doublequote_escape_char=" \t'|&\\*()?~><#$"; const char* doublequote_escape_char=" \t'|&\\*?~><";
uint32_t count_escape_char(std::string& in, uint32_t i, bool doublequote, std::string** estr, uint32_t* ei) {
if( ( doublequote && is_in(in[i], doublequote_escape_char) ) ||
( !doublequote && is_in(in[i], singlequote_escape_char) ) ) {
*estr = &in;
*ei = i;
return 1;
}
else if(in[i] == '\n') // \n: can't remove quotes
return 2;
return 0;
}
uint32_t count_escape_chars(std::string const& in, bool doublequote) uint32_t count_escape_chars(std::string const& in, bool doublequote)
{ {
uint32_t r=0; uint32_t r=0;
@ -91,7 +78,7 @@ uint32_t count_escape_chars(std::string const& in, bool doublequote)
{ {
if(doublequote && is_in(in[i], doublequote_escape_char)) if(doublequote && is_in(in[i], doublequote_escape_char))
r++; r++;
else if(!doublequote && is_in(in[i], singlequote_escape_char)) else if(!doublequote && is_in(in[i], escaped_char))
r++; r++;
else if(in[i] == '\n') // \n: can't remove quotes else if(in[i] == '\n') // \n: can't remove quotes
return 2; return 2;
@ -118,216 +105,117 @@ bool is_this_quote(char c, bool is_doublequote)
return c == '\''; return c == '\'';
} }
bool is_varname(const char c) { void do_one_minify_quotes(string_subarg* in, bool prev_is_var, bool start_quoted)
return is_alphanum(c) || c == '_';
}
void do_minify_quotes(arg_t* in)
{ {
auto t = in->sa.begin(); std::string& val = in->val;
// global loop if(val.size() <= 1)
while(true) return;
{ if(start_quoted) // don't handle start quoted for now
uint32_t i=0; return;
// one iteration loop if(val[0] == '"' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
while(true) return;
if(val[0] == '\'' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
return;
uint32_t i=0, j=0;
while( i < val.size() )
{ {
bool doublequote=false; 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)
{
// 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] == '"') ) while(i<val.size() && !( val[i] == '\'' || val[i] == '"') )
{ {
if(val[i] == '\\') if(val[i] == '\\')
i++; i++;
i++; i++;
} }
// if found: break and go to next step if(i>=val.size()) // end before finding quote: exit
if(i<val.size()) { return;
if(val[i] == '"') if(val[i] == '"')
doublequote=true; doublequote=true;
strstart=&val;
quotestart=i; j=i;
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) if(doublequote)
{ {
while(i<val.size() && val[i] != '"') while(i<val.size() && val[i] != '"')
{ {
if(val[i] == '\\') { if(val[i] == '\\')
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos); i++;
} i++;
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
}
if(i>=val.size()) { // end before finding quote: continue looping
t++;
i=0;
continue;
} }
if(i>=val.size()) // end before finding quote: exit
return;
} }
else else
{ {
while(i<val.size() && val[i] != '\'') while(i<val.size() && val[i] != '\'')
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos); i++;
if(i>=val.size()) { // end before finding quote: continue looping if(i>=val.size()) // end before finding quote: exit
t++; return;
i=0;
continue;
} }
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);
} }
strend=&val; else if(ce == 1) // only one char to escape: can save some space
quoteend=i; {
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; break;
} // end of quote end loop
// has a substitution that can expand: don't dequote
if(!in->forcequoted && has_substitution) {
i++;
continue;
} }
// too many escapes: don't dequote
if(ce > 1) {
i++;
continue;
} }
// removing quotes changes variable name: don't dequote else
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])) ) { for(k=j; k<i-1; k++)
i++; {
continue; if( is_in(val[k], escaped_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, '\\');
} }
// 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);
}
}
}
void do_minify_dollar(subarg_string_t* in)
{
std::string& val = in->val;
for(uint32_t i=0; i<val.size(); i++) {
// skip singlequote strings
if(val[i] == '\'') {
i++;
while(val[i] != '\'')
i++;
}
// has \$
if(i+1<val.size() && val[i] == '\\' && val[i+1] == '$') {
// char after $ is a varname
if(i+2<val.size() && (is_varname(val[i+2]) || is_in(val[i+2], SPECIAL_VARS) || val[i+2] == '{') )
continue;
val.erase(i, 1);
}
}
} }
bool r_minify_useless_quotes(_obj* in) bool r_minify_useless_quotes(_obj* in)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::arg: { case _obj::_arg: {
arg_t* t = dynamic_cast<arg_t*>(in); arg* t = dynamic_cast<arg*>(in);
do_minify_quotes(t); for(uint32_t i=0; i<t->sa.size(); i++)
}; break;
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* t = dynamic_cast<redirect_t*>(in);
if(t->here_document != nullptr)
{ {
recurse(r_minify_useless_quotes, t->target); if(t->sa[i]->type == _obj::subarg_string)
for(auto it: t->here_document->sa)
{ {
if(it->type!=_obj::subarg_string) { string_subarg* ss = dynamic_cast<string_subarg*>(t->sa[i]);
recurse(r_minify_useless_quotes, it); bool prev_is_var=false;
if(i>0 && t->sa[i-1]->type == _obj::subarg_variable)
{
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);
} }
// don't recurse on the rest //if()
return false;
} }
} break; }; break;
default: break; default: break;
} }
return true; return true;
@ -394,53 +282,47 @@ strmap_t gen_minimal_map(countmap_t const& vars, set_t const& excluded)
// calls // calls
strmap_t minify_var(_obj* in, std::regex const& exclude) void minify_var(_obj* in, std::regex const& exclude)
{ {
// countmap_t vars; // countmap_t vars;
set_t excluded; set_t excluded;
strmap_t varmap; strmap_t varmap;
// get vars // get vars
varmap_get(in, exclude); varmap_get(in, exclude);
// concatenate excluded and reserved
concat_sets(excluded, m_excluded_var);
concat_sets(excluded, all_reserved_words);
// create mapping // create mapping
varmap=gen_minimal_map(m_vars, excluded); varmap=gen_minimal_map(m_vars, m_excluded_var);
// perform replace // perform replace
recurse(r_replace_var, in, &varmap); recurse(r_replace_var, in, &varmap);
require_rescan_var(); require_rescan_var();
return varmap;
} }
strmap_t minify_fct(_obj* in, std::regex const& exclude) void minify_fct(_obj* in, std::regex const& exclude)
{ {
// countmap_t fcts, cmdmap; // countmap_t fcts, cmdmap;
set_t excluded, unsets; set_t allcmds, excluded, unsets;
strmap_t fctmap; strmap_t fctmap;
// get fcts and cmds // get fcts and cmds
fctcmdmap_get(in, exclude, regex_null); fctmap_get(in, exclude);
cmdmap_get(in, regex_null);
recurse(r_get_unsets, in, &unsets); recurse(r_get_unsets, in, &unsets);
// concatenate cmds, excluded and reserved // concatenate cmds and excluded commands
excluded=map_to_set(m_cmds); allcmds=map_to_set(m_cmds);
exclude_sets(excluded, map_to_set(m_fcts)); concat_sets(allcmds, m_excluded_fct);
concat_sets(excluded, m_excluded_fct); concat_sets(allcmds, unsets);
concat_sets(excluded, unsets);
concat_sets(excluded, all_reserved_words);
// create mapping // create mapping
m_fcts = combine_common(m_fcts, m_cmds); fctmap=gen_minimal_map(m_fcts, allcmds);
fctmap=gen_minimal_map(m_fcts, excluded);
// perform replace // perform replace
recurse(r_replace_fct, in, &fctmap); recurse(r_replace_fct, in, &fctmap);
require_rescan_fct(); require_rescan_fct();
require_rescan_cmd(); require_rescan_cmd();
return fctmap;
} }
bool delete_unused_fct(_obj* in, std::regex const& exclude) bool delete_unused_fct(_obj* in, std::regex const& exclude)
{ {
set_t unused; set_t unused;
// get fcts and cmds // get fcts and cmds
fctcmdmap_get(in, exclude, regex_null); fctmap_get(in, exclude);
cmdmap_get(in, regex_null);
// find unused fcts // find unused fcts
for(auto it: m_fcts) for(auto it: m_fcts)
{ {
@ -480,248 +362,13 @@ bool delete_unused_var(_obj* in, std::regex const& exclude)
return false; return false;
} }
bool delete_unused_both(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude) void minify_quotes(_obj* in)
{ {
set_t unused_var, unused_fct; recurse(r_minify_useless_quotes, in);
// get all
allmaps_get(in, var_exclude, fct_exclude, regex_null);
// find unused
for(auto it: m_vardefs)
{
if(it.first!="" && m_varcalls.find(it.first) == m_varcalls.end())
unused_var.insert(it.first);
}
for(auto it: m_fcts)
{
if(m_cmds.find(it.first) == m_cmds.end())
unused_fct.insert(it.first);
}
if(unused_var.size()>0 || unused_fct.size()>0)
{
recurse(r_delete_varfct, in, &unused_var, &unused_fct);
require_rescan_all();
return true;
}
return false;
} }
void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude) void delete_unused(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude)
{ {
while(delete_unused_both(in, var_exclude, fct_exclude)); while(delete_unused_fct(in, fct_exclude) || delete_unused_var(in, var_exclude));
// keep deleting until both no deletion // keep deleting until both no function and no variables were deleted
}
// minify ${var} to $var
bool r_minify_empty_manip(_obj* in)
{
switch(in->type)
{
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
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
if(ss->var->index != nullptr) // is a var bash array: skip
return true;
if(i+1<t->sa.size() && t->sa[i+1]->type == _obj::subarg_string)
{
// if next subarg is a string: check its first char
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 == '_')
continue;
}
// if has no actual manipulation operation: set it to not manip
if(ss->var->manip == nullptr || ss->var->manip->sa.size() == 0)
ss->var->is_manip = false;
}
}
}
}; break;
default: break;
}
return true;
}
pipeline_t* do_one_minify_single_block(block_t* in)
{
pipeline_t* ret=nullptr;
list_t* l=nullptr;
if(in->type == _obj::block_brace)
l = dynamic_cast<brace_t*>(in)->lst;
else if(in->type == _obj::block_subshell)
l = dynamic_cast<subshell_t*>(in)->lst;
if(l == nullptr)
return nullptr;
// 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];
// 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;
}
bool r_minify_single_block(_obj* in)
{
switch(in->type)
{
case _obj::pipeline: {
bool has_operated=false;
do
{
// loop operating on current
// (if has operated, current object has changed)
has_operated=false;
pipeline_t* t = dynamic_cast<pipeline_t*>(in);
for(uint32_t i=0; i<t->cmds.size(); i++)
{
pipeline_t* ret = do_one_minify_single_block(t->cmds[i]);
if(ret != nullptr) {
// concatenate redirects
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*>(t->cmds[i])->lst->cls[0]->pls[0] = nullptr;
else if(t->cmds[i]->type == _obj::block_subshell)
dynamic_cast<subshell_t*>(t->cmds[i])->lst->cls[0]->pls[0] = nullptr;
// replace value
delete t->cmds[i];
t->cmds.erase(t->cmds.begin()+i);
for(auto it: ret->cmds) {
t->cmds.insert(t->cmds.begin()+i, it);
i++;
}
has_operated=true;
}
}
}
while(has_operated);
}; break;
default: break;
}
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_do_string_processor(in);
return true;
}
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,26 +20,23 @@ ztd::option_set options( {
ztd::option('c', "stdout", false, "Output result script to stdout"), ztd::option('c', "stdout", false, "Output result script to stdout"),
ztd::option('e', "exec", false, "Directly execute script"), ztd::option('e', "exec", false, "Directly execute script"),
ztd::option("no-shebang", false, "Don't output shebang"), ztd::option("no-shebang", false, "Don't output shebang"),
ztd::option('P', "map", true , "Output var and fct minify map to given file", "file"),
#ifdef DEBUG_MODE #ifdef DEBUG_MODE
ztd::option("\r [Debugging]"), ztd::option("\r [Debugging]"),
ztd::option('J', "json", false, "Output the json structure"), ztd::option('J', "json", false, "Output the json structure"),
#endif #endif
ztd::option("\r [Processing]"), ztd::option("\r [Processing]"),
ztd::option('m', "minify", false, "Minify code without changing functionality"), ztd::option('m', "minify", false, "Minify code without changing functionality"),
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-var --minify-fct --remove-unused"), ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
ztd::option('A', "apply-map", true , "Apply var/fct minify map from given file", "file"), ztd::option("minify-quotes", false, "Remove unnecessary quotes"),
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"), ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
ztd::option('I', "no-include", false, "Don't resolve %include commands"), ztd::option('I', "no-include", false, "Don't resolve %include commands"),
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"), ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
ztd::option("no-extend", false, "Don't add lxsh extension functions"), ztd::option("no-extend", false, "Don't add lxsh extension functions"),
ztd::option("bash", false, "Force bash parsing"),
ztd::option("lxsh", false, "Force lxsh parsing"),
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"), ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
ztd::option("remove-unused", false, "Remove unused functions and variables"), ztd::option("remove-unused", false, "Remove unused functions and variables"),
ztd::option("list-cmd", false, "List all commands invoked in the script"), ztd::option("list-cmd", false, "List all commands invoked in the script"),
ztd::option("\r [Variable processing]"), ztd::option("\r [Variable processing]"),
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing, separated by spaces", "list"), ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"), ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"),
ztd::option("minify-var", false, "Minify variable names"), ztd::option("minify-var", false, "Minify variable names"),
ztd::option("list-var", false, "List all variables set and invoked in the script"), ztd::option("list-var", false, "List all variables set and invoked in the script"),
@ -47,7 +44,7 @@ ztd::option_set options( {
ztd::option("list-var-call", false, "List all variables invoked in the script"), ztd::option("list-var-call", false, "List all variables invoked in the script"),
ztd::option("unset-var", false, "Add 'unset' to all variables at the start of the script to avoid environment interference"), ztd::option("unset-var", false, "Add 'unset' to all variables at the start of the script to avoid environment interference"),
ztd::option("\r [Function processing]"), ztd::option("\r [Function processing]"),
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing, separated by spaces", "list"), ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
ztd::option("minify-fct", false, "Minify function names"), ztd::option("minify-fct", false, "Minify function names"),
ztd::option("list-fct", false, "List all functions defined in the script") ztd::option("list-fct", false, "List all functions defined in the script")
} ); } );
@ -74,36 +71,30 @@ void get_opts()
options['m'].activated=true; options['m'].activated=true;
options["minify-var"].activated=true; options["minify-var"].activated=true;
options["minify-fct"].activated=true; options["minify-fct"].activated=true;
options["minify-quotes"].activated=true;
options["remove-unused"].activated=true; options["remove-unused"].activated=true;
} }
if(options['o'].argument == "-")
options['o'].argument = "/dev/stdout";
if(options['P'].argument == "-")
options['P'].argument = "/dev/stdout";
if(options['A'].argument == "-")
options['A'].argument = "/dev/stdin";
if(
options['A'] && ( options['P'] || options["minify-var"] || options["minify-fct"] )
) {
printf("Incompatible options\n");
exit(ERR_OPT);
}
} }
ztd::option_set create_include_opts() ztd::option_set create_include_opts()
{ {
return std::vector<ztd::option>({ ztd::option_set opts;
opts.add(
ztd::option('e', false, "Escape double quotes"),
ztd::option('C', false, "Don't cd to folder the file is in"), ztd::option('C', false, "Don't cd to folder the file is in"),
ztd::option('f', false, "Force include even if already included. Don't count as included") ztd::option('f', false, "Force include even if already included. Don't count as included")
}); );
return opts;
} }
ztd::option_set create_resolve_opts() ztd::option_set create_resolve_opts()
{ {
return std::vector<ztd::option>({ ztd::option_set opts;
opts.add(
ztd::option('C', false, "Don't cd to folder this file is in"), ztd::option('C', false, "Don't cd to folder this file is in"),
ztd::option('f', false, "Ignore non-zero return values") ztd::option('f', false, "Ignore non-zero return values")
}); );
return opts;
} }
void print_help(const char* arg0) void print_help(const char* arg0)
@ -136,7 +127,7 @@ void print_resolve_help()
printf("Execute shell command and substitute output, from folder of current file\n"); printf("Execute shell command and substitute output, from folder of current file\n");
printf(" - Default behaviour is to parse contents as shell code\n"); printf(" - Default behaviour is to parse contents as shell code\n");
printf(" - Fails if return value is not 0. Can be ignored with -f\n"); printf(" - Fails if return value is not 0. Can be ignored with -f\n");
printf(" - `%%resolve` inside substitutions replaces the substitution and puts raw response\n"); printf(" - `%%include` inside substitutions replaces the substitution and puts raw response\n");
printf("\n"); printf("\n");
ztd::option_set opts=create_resolve_opts(); ztd::option_set opts=create_resolve_opts();

View file

@ -14,14 +14,14 @@
// macro // macro
// constants // constants
const std::set<std::string> posix_cmdvar = { "export", "unset", "local", "read", "getopts" }; const std::vector<std::string> posix_cmdvar = { "export", "unset", "local", "read", "getopts" };
const std::set<std::string> bash_cmdvar = { "readonly", "declare", "typeset" }; const std::vector<std::string> bash_cmdvar = { "readonly", "declare", "typeset" };
const std::set<std::string> arithmetic_precedence_operators = { "!", "~", "+", "-" }; const std::vector<std::string> arithmetic_precedence_operators = { "!", "~", "+", "-" };
const std::set<std::string> arithmetic_operators = { "+", "-", "*", "/", "%", "+=", "-=", "*=", "/=", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" }; const std::vector<std::string> arithmetic_operators = { "+", "-", "*", "/", "+=", "-=", "*=", "/=", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" };
const std::set<std::string> all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" }; const std::vector<std::string> all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" };
const std::set<std::string> out_reserved_words = { "then", "else", "fi", "esac", "do", "done", "}" }; const std::vector<std::string> out_reserved_words = { "then", "else", "fi", "esac", "do", "done", "}" };
// stuff // stuff
@ -103,9 +103,11 @@ parse_context make_context(std::string const& in, std::string const& filename, b
parse_context make_context(parse_context ctx, std::string const& in, std::string const& filename, bool bash) parse_context make_context(parse_context ctx, std::string const& in, std::string const& filename, bool bash)
{ {
if(in != "")
{
ctx.data = in.c_str(); ctx.data = in.c_str();
ctx.size = in.size(); ctx.size = in.size();
}
if(filename != "") if(filename != "")
ctx.filename = filename.c_str(); ctx.filename = filename.c_str();
if(bash) if(bash)
@ -165,18 +167,6 @@ uint32_t skip_unread(const char* in, uint32_t size, uint32_t start)
} }
} }
uint32_t skip_unread_noline(const char* in, uint32_t size, uint32_t start)
{
uint32_t i=start;
while(true)
{
i = skip_chars(in, size, i, SPACES);
if(in[i] != '#') // not a comment
return i;
i = skip_until(in, size, i, "\n"); //skip to endline
}
}
uint32_t word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set) uint32_t word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set)
{ {
uint32_t i=start; uint32_t i=start;
@ -205,9 +195,9 @@ std::pair<std::string,uint32_t> get_word(parse_context ctx, const char* end_set)
// parse fcts // parse fcts
std::pair<variable_t*, parse_context> parse_var(parse_context ctx, bool specialvars, bool array) std::pair<variable*, parse_context> parse_var(parse_context ctx, bool specialvars, bool array)
{ {
variable_t* ret=nullptr; variable* ret=nullptr;
std::string varname; std::string varname;
uint32_t start=ctx.i; uint32_t start=ctx.i;
@ -225,11 +215,11 @@ std::pair<variable_t*, parse_context> parse_var(parse_context ctx, bool specialv
} }
if(varname != "") if(varname != "")
{ {
ret = new variable_t(varname); ret = new variable(varname);
if(ctx.bash && array && ctx[ctx.i]=='[') if(ctx.bash && array && ctx[ctx.i]=='[')
{ {
ctx.i++; ctx.i++;
auto pp=parse_arg(ctx, ARRAY_ARG_END, ARGLIST_END, true, ARG_OPTIMIZE_ARRAY); auto pp=parse_arg(ctx, ARRAY_ARG_END);
ret->index=pp.first; ret->index=pp.first;
ctx = pp.second; ctx = pp.second;
if(ctx[ctx.i] != ']') if(ctx[ctx.i] != ']')
@ -249,7 +239,7 @@ std::pair<std::string, uint32_t> get_operator(parse_context ctx)
std::string ret; std::string ret;
uint32_t start=ctx.i; uint32_t start=ctx.i;
while(!is_alphanum(ctx[ctx.i]) && !is_in(ctx[ctx.i], ARITHMETIC_OPERATOR_END)) while(!is_alphanum(ctx[ctx.i]) && !is_in(ctx[ctx.i], SEPARATORS) && ctx[ctx.i]!=')' )
ctx.i++; ctx.i++;
ret = std::string(ctx.data+start, ctx.i-start); ret = std::string(ctx.data+start, ctx.i-start);
@ -262,9 +252,9 @@ std::pair<std::string, uint32_t> get_operator(parse_context ctx)
// parse an arithmetic // parse an arithmetic
// ends at )) // ends at ))
// temporary, to improve // temporary, to improve
std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx) std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ctx)
{ {
arithmetic_t* ret = nullptr; arithmetic* ret = nullptr;
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
if(ctx.i>ctx.size || ctx[ctx.i] == ')') if(ctx.i>ctx.size || ctx[ctx.i] == ')')
@ -274,16 +264,16 @@ std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
} }
auto po = get_operator(ctx); auto po = get_operator(ctx);
if(is_in_set(po.first, arithmetic_precedence_operators)) if(is_among(po.first, arithmetic_precedence_operators))
{ {
ctx.i = po.second; ctx.i = po.second;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
ret = new arithmetic_operation_t(po.first, pa.first, nullptr, true); ret = new operation_arithmetic(po.first, pa.first, nullptr, true);
ctx=pa.second; ctx=pa.second;
} }
else else
{ {
arithmetic_variable_t* ttvar=nullptr; // for categorizing definitions variable_arithmetic* ttvar=nullptr; // for categorizing definitions
if(ctx[ctx.i]=='-' || is_num(ctx[ctx.i])) if(ctx[ctx.i]=='-' || is_num(ctx[ctx.i]))
{ {
uint32_t j=ctx.i; uint32_t j=ctx.i;
@ -291,40 +281,27 @@ std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++; ctx.i++;
while(is_num(ctx[ctx.i])) while(is_num(ctx[ctx.i]))
ctx.i++; ctx.i++;
ret = new arithmetic_number_t( std::string(ctx.data+j, ctx.i-j) ); ret = new number_arithmetic( std::string(ctx.data+j, ctx.i-j) );
}
else if(word_eq("$((", ctx)) // arithmetics in arithmetics: equivalent to ()
{
ctx.i += 3;
auto pa = parse_arithmetic(ctx);
ret = new arithmetic_parenthesis_t(pa.first);
ctx = pa.second;
ctx.i++;
if(ctx.i >= ctx.size || ctx[ctx.i] != ')') {
parse_error( "Unexpected ')', Expecting '))'", ctx );
return std::make_pair(ret, ctx);
}
ctx.i++;
} }
else if(word_eq("$(", ctx)) else if(word_eq("$(", ctx))
{ {
ctx.i+=2; ctx.i+=2;
auto ps = parse_subshell(ctx); auto ps = parse_subshell(ctx);
ret = new arithmetic_subshell_t(ps.first); ret = new subshell_arithmetic(ps.first);
ctx=ps.second; ctx=ps.second;
} }
else if(word_eq("${", ctx)) else if(word_eq("${", ctx))
{ {
ctx.i+=2; ctx.i+=2;
auto pm = parse_manipulation(ctx); auto pm = parse_manipulation(ctx);
ret = new arithmetic_variable_t(pm.first); ret = new variable_arithmetic(pm.first);
ctx=pm.second; ctx=pm.second;
} }
else if(ctx[ctx.i] == '(') else if(ctx[ctx.i] == '(')
{ {
ctx.i++; ctx.i++;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
ret = new arithmetic_parenthesis_t(pa.first); ret = pa.first;
ctx = pa.second; ctx = pa.second;
ctx.i++; ctx.i++;
} }
@ -337,7 +314,7 @@ std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
ctx.i++; ctx.i++;
} }
auto pp = parse_var(ctx, specialvars, true); auto pp = parse_var(ctx, specialvars, true);
ttvar = new arithmetic_variable_t(pp.first); ttvar = new variable_arithmetic(pp.first);
ret = ttvar; ret = ttvar;
ctx=pp.second; ctx=pp.second;
} }
@ -346,16 +323,16 @@ std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
auto po = get_operator(ctx); auto po = get_operator(ctx);
if(po.first != "") if(po.first != "")
{ {
if(!is_in_set(po.first, arithmetic_operators)) if(!is_among(po.first, arithmetic_operators))
{ {
parse_error( "Unknown arithmetic operator: "+po.first, ctx); parse_error( "Unknown arithmetic operator: "+po.first, ctx);
} }
arithmetic_t* val1 = ret; arithmetic* val1 = ret;
ctx.i=po.second; ctx.i=po.second;
auto pa = parse_arithmetic(ctx); auto pa = parse_arithmetic(ctx);
arithmetic_t* val2 = pa.first; arithmetic* val2 = pa.first;
ctx = pa.second; ctx = pa.second;
ret = new arithmetic_operation_t(po.first, val1, val2); ret = new operation_arithmetic(po.first, val1, val2);
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
} }
@ -377,10 +354,10 @@ std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<variable_t*, parse_context> parse_manipulation(parse_context ctx) std::pair<variable*, parse_context> parse_manipulation(parse_context ctx)
{ {
variable_t* ret = nullptr; variable* ret = nullptr;
arg_t* precede = nullptr; arg* precede = nullptr;
uint32_t start=ctx.i; uint32_t start=ctx.i;
@ -393,7 +370,7 @@ std::pair<variable_t*, parse_context> parse_manipulation(parse_context ctx)
} }
std::string t; std::string t;
t+=ctx[ctx.i]; t+=ctx[ctx.i];
precede = new arg_t( t ); precede = new arg( t );
ctx.i++; ctx.i++;
} }
@ -420,7 +397,7 @@ std::pair<variable_t*, parse_context> parse_manipulation(parse_context ctx)
} }
else if(ctx[ctx.i] != '}') else if(ctx[ctx.i] != '}')
{ {
auto pa = parse_arg(ctx, "}", NULL, false, ARG_OPTIMIZE_MANIP); auto pa = parse_arg(ctx, "}", NULL, false);
ret->manip=pa.first; ret->manip=pa.first;
ctx = pa.second; ctx = pa.second;
} }
@ -429,15 +406,14 @@ std::pair<variable_t*, parse_context> parse_manipulation(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t& j, bool is_quoted) parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j, bool is_quoted)
{ {
if( ctx.i >= ctx.size)
return ctx;
if( ctx[ctx.i] == '`' ) if( ctx[ctx.i] == '`' )
{ {
// add previous subarg // add previous subarg
if(ctx.i-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-j);
ret->add(std::string(ctx.data+j, ctx.i-j)); if(tmpstr!="")
ret->add(tmpstr);
ctx.i++; ctx.i++;
uint32_t k=skip_until(ctx, "`"); uint32_t k=skip_until(ctx, "`");
@ -453,24 +429,23 @@ inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t&
} }
// get subshell // get subshell
parse_context newct = ctx; parse_context newct = ctx;
newct.size=k; ctx.size=k;
auto r=parse_list_until(newct); auto r=parse_list_until(newct);
ret->add(new subarg_subshell_t(new subshell_t(std::get<0>(r)), is_quoted, true)); ret->add(new subshell_subarg(new subshell(std::get<0>(r)), is_quoted));
uint64_t tsize=ctx.size;
ctx = std::get<1>(r); ctx = std::get<1>(r);
ctx.size = tsize;
ctx.i++; ctx.i++;
j = ctx.i; j = ctx.i;
} }
else if( word_eq("$((", ctx) ) // arithmetic operation else if( word_eq("$((", ctx) ) // arithmetic operation
{ {
// add previous subarg // add previous subarg
if(ctx.i-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-j);
ret->add(std::string(ctx.data+j, ctx.i-j)); if(tmpstr!="")
ret->add(tmpstr);
// get arithmetic // get arithmetic
ctx.i+=3; ctx.i+=3;
auto r=parse_arithmetic(ctx); auto r=parse_arithmetic(ctx);
subarg_arithmetic_t* tt = new subarg_arithmetic_t(r.first); arithmetic_subarg* tt = new arithmetic_subarg(r.first);
tt->quoted=is_quoted; tt->quoted=is_quoted;
ret->add(tt); ret->add(tt);
ctx = r.second; ctx = r.second;
@ -487,24 +462,26 @@ inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t&
else if( word_eq("$(", ctx) ) // substitution else if( word_eq("$(", ctx) ) // substitution
{ {
// add previous subarg // add previous subarg
if(ctx.i-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-j);
ret->add(std::string(ctx.data+j, ctx.i-j)); if(tmpstr!="")
ret->add(tmpstr);
// get subshell // get subshell
ctx.i+=2; ctx.i+=2;
auto r=parse_subshell(ctx); auto r=parse_subshell(ctx);
ret->add(new subarg_subshell_t(r.first, is_quoted)); ret->add(new subshell_subarg(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
else if( word_eq("${", ctx) ) // variable manipulation else if( word_eq("${", ctx) ) // variable manipulation
{ {
// add previous subarg // add previous subarg
if(ctx.i-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-j);
ret->add(std::string(ctx.data+j, ctx.i-j)); if(tmpstr!="")
ret->add(tmpstr);
// get manipulation // get manipulation
ctx.i+=2; ctx.i+=2;
auto r=parse_manipulation(ctx); auto r=parse_manipulation(ctx);
ret->add(new subarg_variable_t(r.first, is_quoted)); ret->add(new variable_subarg(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
@ -516,10 +493,11 @@ inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t&
if(r.first !=nullptr) if(r.first !=nullptr)
{ {
// add previous subarg // add previous subarg
if(ctx.i-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-j);
ret->add(std::string(ctx.data+j, ctx.i-j)); if(tmpstr!="")
ret->add(tmpstr);
// add var // add var
ret->add(new subarg_variable_t(r.first, is_quoted)); ret->add(new variable_subarg(r.first, is_quoted));
ctx = r.second; ctx = r.second;
j = ctx.i; j = ctx.i;
} }
@ -531,55 +509,36 @@ inline parse_context do_one_subarg_step(arg_t* ret, parse_context ctx, uint32_t&
return ctx; return ctx;
} }
uint64_t find_any(parse_context const& ctx, const char* chars, uint32_t nchar) {
uint64_t lowest=ctx.size;
uint64_t trank=0;
for(uint32_t i=0; i<nchar; i++) {
const char* tc = strchr(ctx.data+ctx.i, chars[i]);
if(tc != NULL) {
trank = tc-ctx.data;
if(trank < lowest)
lowest = trank;
}
}
return lowest;
}
bool _optimize_skip_arg(parse_context& ctx, const char* str) {
while(ctx.i<ctx.size && !is_in(ctx[ctx.i], str))
ctx.i++;
return true;
}
// parse one argument // parse one argument
// must start at a read char // must start at a read char
// ends at either " \t|&;\n()" // ends at either " \t|&;\n()"
std::pair<arg_t*, parse_context> parse_arg(parse_context ctx, const char* end, const char* unexpected, bool doquote, const char* optimize) std::pair<arg*, parse_context> parse_arg(parse_context ctx, const char* end, const char* unexpected, bool doquote)
{ {
arg_t* ret = new arg_t; arg* ret = new arg;
// j : start of subarg , q = start of quote // j : start of subarg , q = start of quote
uint32_t j=ctx.i,q=ctx.i; uint32_t j=ctx.i,q=ctx.i;
if(unexpected != NULL && is_in(ctx[ctx.i], unexpected)) if(unexpected != NULL && is_in(ctx[ctx.i], unexpected))
{ {
parse_error( unexpected_token(ctx[ctx.i]), ctx); parse_error( unexpected_token(ctx[ctx.i]) , ctx);
} }
while(ctx.i<ctx.size && _optimize_skip_arg(ctx, optimize) && !(end != NULL && is_in(ctx[ctx.i], end)) ) while(ctx.i<ctx.size && !(end != NULL && is_in(ctx[ctx.i], end)) )
{ {
if(ctx.i+1<ctx.size && ctx[ctx.i+1]=='&' && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>')) // special case for <& and >& if(ctx.i+1<ctx.size && is_in(ctx[ctx.i], "<>") && ctx[ctx.i+1]=='&') // special case for <& and >&
{ {
ctx.i += 2; ctx.i += 2;
} }
else if(ctx[ctx.i]=='\\') // backslash: don't check next char else if(doquote && ctx[ctx.i]=='\\') // backslash: don't check next char
{ {
ctx.i++; ctx.i++;
if(ctx.i>=ctx.size) if(ctx.i>=ctx.size)
break; break;
if(ctx[ctx.i] == '\n') // \ on \n : skip this char if(ctx[ctx.i] == '\n') // \ on \n : skip this char
{ {
if(ctx.i-1-j>0) std::string tmpstr=std::string(ctx.data+j, ctx.i-1-j);
ret->add(std::string(ctx.data+j, ctx.i-1-j)); if(tmpstr!="")
ret->add(tmpstr);
ctx.i++; ctx.i++;
j=ctx.i; j=ctx.i;
} }
@ -649,11 +608,8 @@ parse_context parse_heredocument(parse_context ctx)
{ {
ctx.i = ctx.size; ctx.i = ctx.size;
} }
parse_context newctx = make_context(ctx, j); // std::string tmpparse=std::string(ctx.data+j, ctx.i-j);
newctx.size = ctx.i; auto pval = parse_arg({ .data=ctx.data, .size=ctx.i, .i=j, .bash=ctx.bash} , NULL);
auto pval = parse_arg(newctx , NULL, NULL, false, ARG_OPTIMIZE_NULL);
ctx.i = pval.second.i;
ctx.has_errored = pval.second.has_errored;
ctx.here_document->here_document = pval.first; ctx.here_document->here_document = pval.first;
// //
@ -664,19 +620,7 @@ parse_context parse_heredocument(parse_context ctx)
return ctx; return ctx;
} }
std::pair<arg_t*, parse_context> parse_bash_procsub(parse_context ctx) std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
{
if(!ctx.bash)
{
parse_error(strf("bash specific: %c()", ctx[ctx.i]), ctx);
}
bool is_output = ctx[ctx.i] == '>';
ctx.i+=2;
auto ps = parse_subshell(ctx);
return std::make_pair(new arg_t(new subarg_procsub_t(is_output, ps.first)), ps.second);
}
std::pair<redirect_t*, parse_context> parse_redirect(parse_context ctx)
{ {
bool is_redirect=false; bool is_redirect=false;
bool needs_arg=false; bool needs_arg=false;
@ -763,9 +707,9 @@ std::pair<redirect_t*, parse_context> parse_redirect(parse_context ctx)
if(is_redirect) if(is_redirect)
{ {
redirect_t* ret=nullptr; redirect* ret=nullptr;
ret = new redirect_t; ret = new redirect;
ret->op = std::string(ctx.data+start, ctx.i-start); ret->op = std::string(ctx.data+start, ctx.i-start);
if(needs_arg) if(needs_arg)
{ {
@ -801,12 +745,8 @@ std::pair<redirect_t*, parse_context> parse_redirect(parse_context ctx)
} }
else else
{ {
std::pair<arg_t*, parse_context> pa; auto pa = parse_arg(ctx);
if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <() ret->target = pa.first;
pa = parse_bash_procsub(ctx);
else
pa = parse_arg(ctx);
ret->target=pa.first;
ctx=pa.second; ctx=pa.second;
} }
} }
@ -823,9 +763,9 @@ std::pair<redirect_t*, parse_context> parse_redirect(parse_context ctx)
// must start at a read char // must start at a read char
// first char has to be read // first char has to be read
// ends at either &|;\n#() // ends at either &|;\n#()
std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_error, std::vector<redirect_t*>* redirs, bool stop_on_brace) std::pair<arglist*, parse_context> parse_arglist(parse_context ctx, bool hard_error, std::vector<redirect*>* redirs)
{ {
arglist_t* ret = nullptr; arglist* ret = nullptr;
if(word_eq("[[", ctx, ARG_END) ) // [[ bash specific parsing if(word_eq("[[", ctx, ARG_END) ) // [[ bash specific parsing
{ {
@ -836,14 +776,14 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
while(true) while(true)
{ {
if(ret == nullptr) if(ret == nullptr)
ret = new arglist_t; ret = new arglist;
auto pp=parse_arg(ctx, SEPARATORS, NULL, true, ARG_OPTIMIZE_BASHTEST); auto pp=parse_arg(ctx, SEPARATORS, NULL);
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
if(word_eq("]]", ctx, ARG_END)) if(word_eq("]]", ctx, ARG_END))
{ {
ret->add(new arg_t("]]")); ret->add(new arg("]]"));
ctx.i+=2; ctx.i+=2;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
if( !is_in(ctx[ctx.i], ARGLIST_END) ) if( !is_in(ctx[ctx.i], ARGLIST_END) )
@ -860,7 +800,7 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
} }
} }
} }
else if(is_in(ctx[ctx.i], ARGLIST_END) && !word_eq("&>", ctx)) else if(is_in(ctx[ctx.i], SPECIAL_TOKENS) && !word_eq("&>", ctx))
{ {
if(hard_error) if(hard_error)
{ {
@ -876,11 +816,17 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
{ {
if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <() if(ctx.i+1 < ctx.size && (ctx[ctx.i] == '<' || ctx[ctx.i] == '>') && ctx[ctx.i+1] == '(' ) // bash specific <()
{ {
auto pa=parse_bash_procsub(ctx); if(!ctx.bash)
{
parse_error(strf("bash specific: %c()", ctx[ctx.i]), ctx);
}
bool is_output = ctx[ctx.i] == '>';
ctx.i+=2;
if(ret == nullptr) if(ret == nullptr)
ret = new arglist_t; ret = new arglist;
ret->add(pa.first); auto ps = parse_subshell(ctx);
ctx=pa.second; ret->add(new arg(new procsub_subarg(is_output, ps.first)));
ctx=ps.second;
} }
else if(redirs!=nullptr) else if(redirs!=nullptr)
{ {
@ -895,12 +841,10 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
} }
else else
{ {
argparse: ; 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) if(ret == nullptr)
ret = new arglist_t; ret = new arglist;
auto pp=parse_arg(ctx);
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
} }
@ -914,7 +858,7 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
} }
if(ctx.i>=ctx.size) if(ctx.i>=ctx.size)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
if( is_in(ctx[ctx.i], ARGLIST_END) ) if( is_in(ctx[ctx.i], SPECIAL_TOKENS) )
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
@ -927,33 +871,23 @@ std::pair<arglist_t*, parse_context> parse_arglist(parse_context ctx, bool hard_
// must start at a read char // must start at a read char
// separated by | // separated by |
// ends at either &;\n#) // ends at either &;\n#)
std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ctx) std::pair<pipeline*, parse_context> parse_pipeline(parse_context ctx)
{ {
pipeline_t* ret = new pipeline_t; pipeline* ret = new pipeline;
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)) if(ctx[ctx.i] == '!' && ctx.i+1<ctx.size && is_in(ctx[ctx.i+1], SPACES))
{ {
ret->negated = ret->negated ? false : true; ret->negated = true;
ctx.i++; ctx.i++;
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
} else if(ctx.bash && wp.first == "time" ) {
ret->bash_time = true;
ctx.i+=4;
ctx.i=skip_chars(ctx, SPACES);
} else {
break;
} }
}
while(ctx.i<ctx.size) while(ctx.i<ctx.size)
{ {
auto pp=parse_block(ctx); auto pp=parse_block(ctx);
ret->add(pp.first); ret->add(pp.first);
ctx = pp.second; ctx = pp.second;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
if( ctx.i>=ctx.size || is_in(ctx[ctx.i], PIPELINE_END) || word_eq("||", ctx) || ctx[ctx.i] == '}' ) if( ctx.i>=ctx.size || is_in(ctx[ctx.i], PIPELINE_END) || word_eq("||", ctx) )
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
else if( ctx[ctx.i] != '|' ) else if( ctx[ctx.i] != '|' )
{ {
@ -961,14 +895,6 @@ std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
ctx.i++; ctx.i++;
if(ctx.here_document != nullptr)
{
ctx.i = skip_unread_noline(ctx);
if(ctx[ctx.i] == '\n')
ctx = parse_heredocument(ctx+1);
}
else
ctx.i = skip_unread(ctx);
} }
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
@ -977,9 +903,9 @@ std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ctx)
// must start at a read char // must start at a read char
// separated by && or || // separated by && or ||
// ends at either ;\n)# // ends at either ;\n)#
std::pair<condlist_t*, parse_context> parse_condlist(parse_context ctx) std::pair<condlist*, parse_context> parse_condlist(parse_context ctx)
{ {
condlist_t* ret = new condlist_t; condlist* ret = new condlist;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
bool optype=AND_OP; bool optype=AND_OP;
@ -988,7 +914,7 @@ std::pair<condlist_t*, parse_context> parse_condlist(parse_context ctx)
auto pp=parse_pipeline(ctx); auto pp=parse_pipeline(ctx);
ret->add(pp.first, optype); ret->add(pp.first, optype);
ctx = pp.second; ctx = pp.second;
if(ctx.i>=ctx.size || is_in(ctx[ctx.i], CONTROL_END) || is_in(ctx[ctx.i], COMMAND_SEPARATOR) || ctx[ctx.i] == '}') // 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)) // end here exactly: used for control later
{ {
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
@ -1013,13 +939,6 @@ std::pair<condlist_t*, parse_context> parse_condlist(parse_context ctx)
parse_error( unexpected_token(ctx[ctx.i]), ctx); parse_error( unexpected_token(ctx[ctx.i]), ctx);
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
if(ctx.here_document != nullptr)
{
ctx.i = skip_unread_noline(ctx);
if(ctx[ctx.i] == '\n')
ctx = parse_heredocument(ctx+1);
}
else
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
if(ctx.i>=ctx.size) if(ctx.i>=ctx.size)
{ {
@ -1030,9 +949,9 @@ std::pair<condlist_t*, parse_context> parse_condlist(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ctx, list_parse_options opts) std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx, list_parse_options opts)
{ {
list_t* ret = new list_t; list* ret = new list;
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
std::string found_end_word; std::string found_end_word;
@ -1105,35 +1024,27 @@ std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context c
if(ctx.here_document != nullptr) if(ctx.here_document != nullptr)
{ {
bool has_parsed=false; uint8_t do_twice=2;
parse_context t_ctx=ctx; // case of : cat << EOF ;
if(t_ctx[t_ctx.i] == '\n') while(do_twice>0)
{ {
t_ctx = parse_heredocument(t_ctx+1); if(ctx[ctx.i] == '\n')
has_parsed=true;
}
else if(t_ctx[t_ctx.i] == '#')
{ {
t_ctx.i = skip_until(t_ctx, "\n"); //skip to endline ctx = parse_heredocument(ctx+1);
t_ctx = parse_heredocument(t_ctx+1); break;
has_parsed=true;
} }
else if(t_ctx[t_ctx.i] == ';') { else if(ctx[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); ctx.i = skip_until(ctx, "\n"); //skip to endline
has_parsed=true; ctx = parse_heredocument(ctx+1);
break;
} }
else if(t_ctx[t_ctx.i] == '#') skip_chars(ctx, SPACES);
{ do_twice--;
t_ctx.i = skip_until(t_ctx, "\n"); //skip to endline
t_ctx = parse_heredocument(t_ctx+1);
has_parsed=true;
} }
} // case of : cat << EOF ; ;
if(has_parsed) if(do_twice==0 && is_in(ctx[ctx.i], COMMAND_SEPARATOR))
ctx = t_ctx; parse_error( unexpected_token(ctx[ctx.i]), ctx);
} }
if(is_in(ctx[ctx.i], COMMAND_SEPARATOR)) if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
@ -1160,9 +1071,9 @@ std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context c
// parse a subshell // parse a subshell
// must start right after the opening ( // must start right after the opening (
// ends at ) and nothing else // ends at ) and nothing else
std::pair<subshell_t*, parse_context> parse_subshell(parse_context ctx) std::pair<subshell*, parse_context> parse_subshell(parse_context ctx)
{ {
subshell_t* ret = new subshell_t; subshell* ret = new subshell;
uint32_t start=ctx.i; uint32_t start=ctx.i;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
@ -1182,9 +1093,9 @@ std::pair<subshell_t*, parse_context> parse_subshell(parse_context ctx)
// parse a brace block // parse a brace block
// must start right after the opening { // must start right after the opening {
// ends at } and nothing else // ends at } and nothing else
std::pair<brace_t*, parse_context> parse_brace(parse_context ctx) std::pair<brace*, parse_context> parse_brace(parse_context ctx)
{ {
brace_t* ret = new brace_t; brace* ret = new brace;
uint32_t start=ctx.i; uint32_t start=ctx.i;
ctx.i = skip_unread(ctx); ctx.i = skip_unread(ctx);
@ -1204,9 +1115,9 @@ std::pair<brace_t*, parse_context> parse_brace(parse_context ctx)
// parse a function // parse a function
// must start right after the () // must start right after the ()
// then parses a brace block // then parses a brace block
std::pair<function_t*, parse_context> parse_function(parse_context ctx, const char* after) std::pair<function*, parse_context> parse_function(parse_context ctx, const char* after)
{ {
function_t* ret = new function_t; function* ret = new function;
ctx.i=skip_unread(ctx); ctx.i=skip_unread(ctx);
if(ctx[ctx.i] != '{') if(ctx[ctx.i] != '{')
@ -1232,7 +1143,7 @@ std::pair<function_t*, parse_context> parse_function(parse_context ctx, const ch
} }
// parse only var assigns // parse only var assigns
parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=false, std::string const& cmd="") parse_context parse_cmd_varassigns(cmd* ret, parse_context ctx, bool cmdassign=false, std::string const& cmd="")
{ {
bool forbid_assign=false; bool forbid_assign=false;
bool forbid_special=false; bool forbid_special=false;
@ -1241,10 +1152,6 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
if(cmdassign && (forbid_special || cmd == "export") ) if(cmdassign && (forbid_special || cmd == "export") )
forbid_special=true; forbid_special=true;
std::vector<std::pair<variable_t*,arg_t*>>* ret=&in->var_assigns;
if(cmdassign)
ret=&in->cmd_var_assigns;
while(ctx.i<ctx.size && !is_in(ctx[ctx.i], ARGLIST_END)) while(ctx.i<ctx.size && !is_in(ctx[ctx.i], ARGLIST_END))
{ {
auto vp=parse_var(ctx, false, true); auto vp=parse_var(ctx, false, true);
@ -1277,7 +1184,7 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
else else
ctx.i++; ctx.i++;
arg_t* ta=nullptr; arg* ta=nullptr;
if(ctx[ctx.i] == '(') // bash var=() if(ctx[ctx.i] == '(') // bash var=()
{ {
if(!ctx.bash) if(!ctx.bash)
@ -1289,7 +1196,7 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
parse_error("Unallowed special assign", ctx); parse_error("Unallowed special assign", ctx);
} }
ctx.i++; ctx.i++;
auto pp=parse_arg(ctx, ")", "", false, ARG_OPTIMIZE_DEFARR); auto pp=parse_arg(ctx, ")");
ta=pp.first; ta=pp.first;
ta->insert(0,"("); ta->insert(0,"(");
ta->add(")"); ta->add(")");
@ -1298,7 +1205,7 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
} }
else if( is_in(ctx[ctx.i], ARG_END) ) // no value : give empty value else if( is_in(ctx[ctx.i], ARG_END) ) // no value : give empty value
{ {
ta = new arg_t; ta = new arg;
} }
else else
{ {
@ -1307,8 +1214,7 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
ctx=pp.second; ctx=pp.second;
} }
ta->insert(0, strop); ta->insert(0, strop);
ta->forcequoted = !cmdassign; ret->var_assigns.push_back(std::make_pair(vp.first, ta));
ret->push_back(std::make_pair(vp.first, ta));
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
} }
else else
@ -1317,14 +1223,14 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
{ {
if(vp.first != nullptr && is_in(newct[newct.i], ARG_END) ) if(vp.first != nullptr && is_in(newct[newct.i], ARG_END) )
{ {
ret->push_back(std::make_pair(vp.first, nullptr)); ret->var_assigns.push_back(std::make_pair(vp.first, nullptr));
ctx=newct; ctx=newct;
} }
else else
{ {
delete vp.first; delete vp.first;
auto pp=parse_arg(ctx); auto pp=parse_arg(ctx);
ret->push_back(std::make_pair(nullptr, pp.first)); ret->var_assigns.push_back(std::make_pair(nullptr, pp.first));
ctx=pp.second; ctx=pp.second;
} }
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
@ -1341,36 +1247,41 @@ parse_context parse_cmd_varassigns(cmd_t* in, parse_context ctx, bool cmdassign=
} }
// must start at read char // must start at read char
std::pair<cmd_t*, parse_context> parse_cmd(parse_context ctx) std::pair<cmd*, parse_context> parse_cmd(parse_context ctx)
{ {
cmd_t* ret = new cmd_t; cmd* ret = new cmd;
uint32_t start=ctx.i;
ctx = parse_cmd_varassigns(ret, ctx); ctx = parse_cmd_varassigns(ret, ctx);
auto wp=get_word(ctx, ARG_END); auto wp=get_word(ctx, ARG_END);
bool is_bash_cmdvar=false; if(is_in_vector(wp.first, posix_cmdvar) || is_in_vector(wp.first, bash_cmdvar))
if(is_in_set(wp.first, posix_cmdvar) || (is_bash_cmdvar=is_in_set(wp.first, bash_cmdvar)) )
{ {
if(!ctx.bash && (is_bash_cmdvar || is_in_set(wp.first, bash_cmdvar))) if(!ctx.bash && is_in_vector(wp.first, bash_cmdvar))
{ {
parse_error("bash specific: "+wp.first, ctx); parse_error("bash specific: "+wp.first, ctx);
} }
if(ret->var_assigns.size()>0)
{
parse_error("Unallowed preceding variables on "+wp.first, ctx, start);
}
ret->args = new arglist_t; ret->args = new arglist;
ret->args->add(new arg_t(wp.first)); ret->args->add(new arg(wp.first));
ret->is_cmdvar=true; ret->is_cmdvar=true;
ctx.i = wp.second; ctx.i = wp.second;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
ctx = parse_cmd_varassigns(ret, ctx, true, wp.first); ctx = parse_cmd_varassigns(ret, ctx, true, wp.first);
} }
else if(!is_in(ctx[ctx.i], ARGLIST_END))
if(!is_in(ctx[ctx.i], SPECIAL_TOKENS))
{ {
auto pp=parse_arglist(ctx, true, &ret->redirs); auto pp=parse_arglist(ctx, true, &ret->redirs);
ret->args = pp.first; ret->args = pp.first;
ctx = pp.second; ctx = pp.second;
} }
else if( ret->var_assigns.size() <= 0 ) else if(ret->var_assigns.size() <= 0)
{ {
parse_error( unexpected_token(ctx[ctx.i]), ctx ); parse_error( unexpected_token(ctx[ctx.i]), ctx );
ctx.i++; ctx.i++;
@ -1382,9 +1293,9 @@ std::pair<cmd_t*, parse_context> parse_cmd(parse_context ctx)
// parse a case block // parse a case block
// must start right after the case // must start right after the case
// ends at } and nothing else // ends at } and nothing else
std::pair<case_t*, parse_context> parse_case(parse_context ctx) std::pair<case_block*, parse_context> parse_case(parse_context ctx)
{ {
case_t* ret = new case_t; case_block* ret = new case_block;
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
// get the treated argument // get the treated argument
@ -1406,7 +1317,7 @@ std::pair<case_t*, parse_context> parse_case(parse_context ctx)
while(ctx.i<ctx.size && !word_eq("esac", ctx, ARG_END) ) while(ctx.i<ctx.size && !word_eq("esac", ctx, ARG_END) )
{ {
// add one element // add one element
ret->cases.push_back( std::make_pair(std::vector<arg_t*>(), nullptr) ); ret->cases.push_back( std::make_pair(std::vector<arg*>(), nullptr) );
// iterator to last element // iterator to last element
auto cc = ret->cases.end()-1; auto cc = ret->cases.end()-1;
@ -1428,7 +1339,7 @@ std::pair<case_t*, parse_context> parse_case(parse_context ctx)
} }
if(ctx[ctx.i] == ')') if(ctx[ctx.i] == ')')
break; break;
if(is_in(ctx[ctx.i], PIPELINE_END)) if(ctx[ctx.i] != '|' && is_in(ctx[ctx.i], SPECIAL_TOKENS))
{ {
parse_error( unexpected_token(ctx[ctx.i])+", expecting ')'", ctx ); parse_error( unexpected_token(ctx[ctx.i])+", expecting ')'", ctx );
} }
@ -1472,9 +1383,9 @@ std::pair<case_t*, parse_context> parse_case(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<if_t*, parse_context> parse_if(parse_context ctx) std::pair<if_block*, parse_context> parse_if(parse_context ctx)
{ {
if_t* ret = new if_t; if_block* ret = new if_block;
while(true) while(true)
{ {
@ -1503,10 +1414,6 @@ std::pair<if_t*, parse_context> parse_if(parse_context ctx)
newctx.has_errored=true; newctx.has_errored=true;
} }
ctx = newctx; ctx = newctx;
if(ctx.i >= ctx.size)
{
return std::make_pair(ret, ctx);
}
if(word == "fi") if(word == "fi")
break; break;
@ -1531,9 +1438,9 @@ std::pair<if_t*, parse_context> parse_if(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<for_t*, parse_context> parse_for(parse_context ctx) std::pair<for_block*, parse_context> parse_for(parse_context ctx)
{ {
for_t* ret = new for_t; for_block* ret = new for_block;
ctx.i = skip_chars(ctx, SPACES); ctx.i = skip_chars(ctx, SPACES);
auto wp = get_word(ctx, ARG_END); auto wp = get_word(ctx, ARG_END);
@ -1542,7 +1449,7 @@ std::pair<for_t*, parse_context> parse_for(parse_context ctx)
{ {
parse_error( strf("Bad variable name in for clause: '%s'", wp.first.c_str()), ctx ); parse_error( strf("Bad variable name in for clause: '%s'", wp.first.c_str()), ctx );
} }
ret->var = new variable_t(wp.first, nullptr, true); ret->var = new variable(wp.first, nullptr, true);
ctx.i = wp.second; ctx.i = wp.second;
ctx.i=skip_chars(ctx, SPACES); ctx.i=skip_chars(ctx, SPACES);
@ -1555,7 +1462,6 @@ std::pair<for_t*, parse_context> parse_for(parse_context ctx)
auto pp = parse_arglist(ctx, false); auto pp = parse_arglist(ctx, false);
ret->iter = pp.first; ret->iter = pp.first;
ctx = pp.second; ctx = pp.second;
ret->in_val=true;
} }
else if(wp.first != "") else if(wp.first != "")
{ {
@ -1595,9 +1501,9 @@ std::pair<for_t*, parse_context> parse_for(parse_context ctx)
return std::make_pair(ret, ctx); return std::make_pair(ret, ctx);
} }
std::pair<while_t*, parse_context> parse_while(parse_context ctx) std::pair<while_block*, parse_context> parse_while(parse_context ctx)
{ {
while_t* ret = new while_t; while_block* ret = new while_block;
// cond // cond
parse_context oldctx = ctx; parse_context oldctx = ctx;
@ -1627,10 +1533,10 @@ std::pair<while_t*, parse_context> parse_while(parse_context ctx)
} }
// detect if brace, subshell, case or other // detect if brace, subshell, case or other
std::pair<block_t*, parse_context> parse_block(parse_context ctx) std::pair<block*, parse_context> parse_block(parse_context ctx)
{ {
ctx.i = skip_chars(ctx, SEPARATORS); ctx.i = skip_chars(ctx, SEPARATORS);
block_t* ret = nullptr; block* ret = nullptr;
if(ctx.i>=ctx.size) if(ctx.i>=ctx.size)
{ {
@ -1688,10 +1594,9 @@ std::pair<block_t*, parse_context> parse_block(parse_context ctx)
ret = pp.first; ret = pp.first;
ctx = pp.second; ctx = pp.second;
} }
else if(is_in_set(word, out_reserved_words)) // is a reserved word else if(is_in_vector(word, out_reserved_words)) // is a reserved word
{ {
parse_error( strf("Unexpected '%s'", word.c_str())+expecting(ctx.expecting) , ctx); parse_error( strf("Unexpected '%s'", word.c_str())+expecting(ctx.expecting) , ctx);
ctx.i+=word.size();
} }
// end reserved words // end reserved words
else if( word == "function" ) // bash style function else if( word == "function" ) // bash style function
@ -1746,11 +1651,11 @@ std::pair<block_t*, parse_context> parse_block(parse_context ctx)
} }
if(ret!=nullptr && ret->type != block_t::block_cmd) if(ret->type != block::block_cmd)
{ {
uint32_t j=skip_chars(ctx, SPACES); uint32_t j=skip_chars(ctx, SPACES);
ctx.i=j; ctx.i=j;
auto pp=parse_arglist(ctx, false, &ret->redirs, true); // in case of redirects auto pp=parse_arglist(ctx, false, &ret->redirs); // in case of redirects
if(pp.first != nullptr) if(pp.first != nullptr)
{ {
delete pp.first; delete pp.first;

View file

@ -27,6 +27,7 @@ set_t m_excluded_var, m_excluded_fct, m_excluded_cmd;
bool b_gotvar=false, b_gotfct=false, b_gotcmd=false; bool b_gotvar=false, b_gotfct=false, b_gotcmd=false;
// requires // requires
void require_rescan_var() void require_rescan_var()
@ -62,24 +63,16 @@ void require_rescan_all()
// type tools // type tools
countmap_t combine_maps(countmap_t const& a, countmap_t const& b) countmap_t combine_maps(countmap_t const& a, countmap_t const& b)
{ {
countmap_t ret = a; countmap_t ret;
for(auto it: b) for(auto it: a)
{ {
if(!ret.insert( it ).second) if(!ret.insert( it ).second)
ret[it.first] += it.second; ret[it.first] += it.second;
} }
return ret; for(auto it: b)
}
// add the values of b to a only if they are already present in a
countmap_t combine_common(countmap_t const& a, countmap_t const& b)
{
countmap_t ret = a;
for(auto it: a)
{ {
auto t=b.find(it.first); if(!ret.insert( it ).second)
if(t!=b.end()) ret[it.first] += it.second;
ret[it.first] += t->second;
} }
return ret; return ret;
} }
@ -155,7 +148,7 @@ std::string get_varname(std::string const& in)
return in; return in;
} }
std::string get_varname(arg_t* in) std::string get_varname(arg* in)
{ {
if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string) if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string)
return ""; return "";
@ -167,15 +160,15 @@ std::string get_varname(arg_t* in)
bool cmd_is_argvar(std::string const& in) bool cmd_is_argvar(std::string const& in)
{ {
return is_in_set(in, posix_cmdvar) || is_in_set(in, bash_cmdvar); return is_in_vector(in, posix_cmdvar) || is_in_vector(in, bash_cmdvar);
} }
bool cmd_t::is_argvar() bool cmd::is_argvar()
{ {
return is_cmdvar; return is_cmdvar;
} }
bool cmd_t::is(std::string const& in) bool cmd::is(std::string const& in)
{ {
return in == this->arg_string(0); return in == this->arg_string(0);
} }
@ -213,39 +206,6 @@ void cmdmap_get(_obj* in, std::regex const& exclude)
} }
} }
void fctcmdmap_get(_obj* in, std::regex const& exclude_fct, std::regex const& exclude_cmd)
{
if(!b_gotcmd && !b_gotfct) {
b_gotcmd = b_gotfct = true;
recurse(r_get_fctcmd, in, &m_cmds, &m_fcts);
m_excluded_fct = prune_matching(m_cmds, exclude_cmd);
concat_sets(m_excluded_fct, prune_matching(m_fcts, exclude_fct));
}
else {
cmdmap_get(in, exclude_fct);
fctmap_get(in, exclude_cmd);
}
}
void allmaps_get(_obj* in, std::regex const& exclude_var, std::regex const& exclude_fct, std::regex const& exclude_cmd)
{
if(!b_gotvar && !b_gotcmd && !b_gotfct)
{
b_gotvar = b_gotcmd = b_gotfct = true;
recurse(r_get_all, in, &m_vardefs, &m_varcalls, &m_cmds, &m_fcts);
m_excluded_fct = prune_matching(m_cmds, exclude_cmd);
concat_sets(m_excluded_fct, prune_matching(m_fcts, exclude_fct));
m_vars = combine_maps(m_vardefs, m_varcalls);
m_excluded_var = prune_matching(m_vars, exclude_var);
}
else
{
varmap_get(in, exclude_var);
cmdmap_get(in, exclude_fct);
fctmap_get(in, exclude_fct);
}
}
/** OUTPUT **/ /** OUTPUT **/
void list_vars(_obj* in, std::regex const& exclude) void list_vars(_obj* in, std::regex const& exclude)
@ -285,53 +245,28 @@ void add_unset_variables(shmain* sh, std::regex const& exclude)
varmap_get(sh, exclude); varmap_get(sh, exclude);
if(m_vars.size()>0) if(m_vars.size()>0)
{ {
cmd_t* unset_cmd = new cmd_t; cmd* unset_cmd = new cmd;
unset_cmd->add(new arg_t("unset")); unset_cmd->add(new arg("unset"));
unset_cmd->is_cmdvar=true; unset_cmd->is_cmdvar=true;
for(auto it: m_vars) for(auto it: m_vars)
{ {
unset_cmd->cmd_var_assigns.push_back(std::make_pair(new variable_t(it.first), nullptr)); unset_cmd->var_assigns.push_back(std::make_pair(new variable(it.first), nullptr));
} }
condlist_t* cl = new condlist_t(unset_cmd); condlist* cl = new condlist(unset_cmd);
sh->lst->cls.insert(sh->lst->cls.begin(), cl); sh->lst->cls.insert(sh->lst->cls.begin(), cl);
} }
} }
bool has_env_set(_obj* in) {
bool r=false;
recurse(r_has_env_set, in, &r);
return r;
}
/** RECURSIVES **/ /** RECURSIVES **/
// CHECK //
bool r_has_env_set(_obj* in, bool* result)
{
switch(in->type)
{
case _obj::block_subshell: {
return false;
}; break;
case _obj::block_cmd: {
cmd_t* t = dynamic_cast<cmd_t*>(in);
if(t->has_var_assign() || t->arg_string(0) == "cd")
*result = true;
}
default: break;
}
return true;
}
// GET // // GET //
bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap) bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::variable: { case _obj::_variable: {
variable_t* t = dynamic_cast<variable_t*>(in); variable* t = dynamic_cast<variable*>(in);
if(t->definition) if(t->definition)
{ {
if(!defmap->insert( std::make_pair(t->varname, 1) ).second) if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
@ -353,10 +288,10 @@ bool r_get_unsets(_obj* in, set_t* unsets)
switch(in->type) switch(in->type)
{ {
case _obj::block_cmd: { case _obj::block_cmd: {
cmd_t* t = dynamic_cast<cmd_t*>(in); cmd* t = dynamic_cast<cmd*>(in);
if(t->is("unset")) if(t->is("unset"))
{ {
for(auto it: t->cmd_var_assigns) for(auto it: t->var_assigns)
{ {
if(it.first != nullptr) if(it.first != nullptr)
unsets->insert(it.first->varname); unsets->insert(it.first->varname);
@ -373,7 +308,7 @@ bool r_get_cmd(_obj* in, countmap_t* all_cmds)
switch(in->type) switch(in->type)
{ {
case _obj::block_cmd: { case _obj::block_cmd: {
cmd_t* t = dynamic_cast<cmd_t*>(in); cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->arg_string(0); std::string cmdname = t->arg_string(0);
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second) if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++; (*all_cmds)[cmdname]++;
@ -388,7 +323,7 @@ bool r_get_fct(_obj* in, countmap_t* fct_map)
switch(in->type) switch(in->type)
{ {
case _obj::block_function: { case _obj::block_function: {
function_t* t = dynamic_cast<function_t*>(in); function* t = dynamic_cast<function*>(in);
if(!fct_map->insert( std::make_pair(t->name, 1) ).second) if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
(*fct_map)[t->name]++; (*fct_map)[t->name]++;
}; break; }; break;
@ -397,35 +332,20 @@ bool r_get_fct(_obj* in, countmap_t* fct_map)
return true; return true;
} }
bool r_get_fctcmd(_obj* in, countmap_t* all_cmds, countmap_t* fct_map)
{
r_get_cmd(in, all_cmds);
r_get_fct(in, fct_map);
return true;
}
bool r_get_all(_obj* in, countmap_t* defmap, countmap_t* callmap, countmap_t* all_cmds, countmap_t* fct_map)
{
r_get_var(in, defmap, callmap);
r_get_cmd(in, all_cmds);
r_get_fct(in, fct_map);
return true;
}
// DELETE // // DELETE //
bool r_delete_fct(_obj* in, set_t* fcts) bool r_delete_fct(_obj* in, set_t* fcts)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::list: { case _obj::_list: {
list_t* t = dynamic_cast<list_t*>(in); list* t = dynamic_cast<list*>(in);
for(uint32_t i=0; i<t->cls.size(); i++) for(uint32_t i=0; i<t->cls.size(); i++)
{ {
block_t* tb = t->cls[i]->first_block(); block* tb = t->cls[i]->first_block();
if(tb != nullptr && tb->type == _obj::block_function) if(tb != nullptr && tb->type == _obj::block_function)
{ {
function_t* fc = dynamic_cast<function_t*>(tb); function* fc = dynamic_cast<function*>(tb);
if(fcts->find(fc->name)!=fcts->end()) if(fcts->find(fc->name)!=fcts->end())
{ {
delete t->cls[i]; delete t->cls[i];
@ -444,16 +364,16 @@ bool r_delete_var(_obj* in, set_t* vars)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::list: { case _obj::_list: {
list_t* t = dynamic_cast<list_t*>(in); list* t = dynamic_cast<list*>(in);
for(uint32_t i=0; i<t->cls.size(); i++) for(uint32_t i=0; i<t->cls.size(); i++)
{ {
block_t* tb = t->cls[i]->first_block(); block* tb = t->cls[i]->first_block();
bool to_delete=false; bool to_delete=false;
bool has_deleted=false; bool has_deleted=false;
if(tb != nullptr && tb->type == _obj::block_cmd) if(tb != nullptr && tb->type == _obj::block_cmd)
{ {
cmd_t* c = dynamic_cast<cmd_t*>(tb); cmd* c = dynamic_cast<cmd*>(tb);
for(uint32_t j=0; j<c->var_assigns.size(); j++) for(uint32_t j=0; j<c->var_assigns.size(); j++)
{ {
@ -471,22 +391,6 @@ bool r_delete_var(_obj* in, set_t* vars)
if(has_deleted && c->var_assigns.size()<=0 && (c->arglist_size()<=0 || c->is_cmdvar) ) if(has_deleted && c->var_assigns.size()<=0 && (c->arglist_size()<=0 || c->is_cmdvar) )
to_delete=true; to_delete=true;
for(uint32_t j=0; j<c->cmd_var_assigns.size(); j++)
{
if( c->cmd_var_assigns[j].first != nullptr && vars->find(c->cmd_var_assigns[j].first->varname) != vars->end() )
{
if(c->cmd_var_assigns[j].first != nullptr)
delete c->cmd_var_assigns[j].first;
if(c->cmd_var_assigns[j].second != nullptr)
delete c->cmd_var_assigns[j].second;
c->cmd_var_assigns.erase(c->cmd_var_assigns.begin()+j);
has_deleted=true;
j--;
}
}
if(has_deleted && c->cmd_var_assigns.size()<=0 && (c->arglist_size()<=0 || c->is_cmdvar) )
to_delete=true;
} }
if(to_delete) if(to_delete)
{ {
@ -494,8 +398,6 @@ bool r_delete_var(_obj* in, set_t* vars)
t->cls.erase(t->cls.begin()+i); t->cls.erase(t->cls.begin()+i);
i--; i--;
} }
if(t->cls.size()<=0)
t->add(make_condlist("true"));
} }
} }
default: break; default: break;
@ -503,13 +405,6 @@ bool r_delete_var(_obj* in, set_t* vars)
return true; return true;
} }
bool r_delete_varfct(_obj* in, set_t* vars, set_t* fcts)
{
r_delete_var(in, vars);
r_delete_fct(in, fcts);
return true;
}
std::set<std::string> find_lxsh_commands(shmain* sh) std::set<std::string> find_lxsh_commands(shmain* sh)
{ {
std::set<std::string> ret; std::set<std::string> ret;
@ -549,7 +444,7 @@ bool r_do_string_processor(_obj* in)
{ {
if(in->type == _obj::subarg_string) if(in->type == _obj::subarg_string)
{ {
subarg_string_t* t = dynamic_cast<subarg_string_t*>(in); string_subarg* t = dynamic_cast<string_subarg*>(in);
auto v = get_processors(t->val); auto v = get_processors(t->val);
if(v.find("LXSH_PARSE_MINIFY") != v.end()) if(v.find("LXSH_PARSE_MINIFY") != v.end())
{ {
@ -560,8 +455,8 @@ bool r_do_string_processor(_obj* in)
require_rescan_all(); require_rescan_all();
if(options["remove-unused"]) if(options["remove-unused"])
delete_unused( tsh, re_var_exclude, re_fct_exclude ); delete_unused( tsh, re_var_exclude, re_fct_exclude );
if(options["minify"]) if(options["minify-quotes"])
minify_generic(tsh); minify_quotes(tsh);
if(options["minify-var"]) if(options["minify-var"])
minify_var( tsh, re_var_exclude ); minify_var( tsh, re_var_exclude );
if(options["minify-fct"]) if(options["minify-fct"])
@ -582,17 +477,14 @@ bool r_do_string_processor(_obj* in)
void string_processors(_obj* in) void string_processors(_obj* in)
{ {
// recurse(r_do_string_processor, in); recurse(r_do_string_processor, in);
;
} }
/** JSON **/ /** JSON **/
#ifdef DEBUG_MODE
std::string quote_string(std::string const& in) std::string quote_string(std::string const& in)
{ {
return '"' + stringReplace(stringReplace(stringReplace(in, "\\", "\\\\"), "\"", "\\\""), "\n", "\\n") + '"'; return '"' + stringReplace(in, "\"", "\\\"") + '"';
} }
std::string gen_json(std::vector<std::pair<std::string,std::string>> const& vec) std::string gen_json(std::vector<std::pair<std::string,std::string>> const& vec)
@ -627,6 +519,7 @@ std::string boolstring(bool in)
return "false"; return "false";
} }
#ifdef DEBUG_MODE
std::string gen_json_struc(_obj* o) std::string gen_json_struc(_obj* o)
{ {
if(o==nullptr) if(o==nullptr)
@ -634,9 +527,9 @@ std::string gen_json_struc(_obj* o)
std::vector<std::pair<std::string,std::string>> vec; std::vector<std::pair<std::string,std::string>> vec;
switch(o->type) switch(o->type)
{ {
case _obj::variable : case _obj::_variable :
{ {
variable_t* t = dynamic_cast<variable_t*>(o); variable* t = dynamic_cast<variable*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) );
vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname))); vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname)));
vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition))); vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition)));
@ -646,29 +539,27 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) ); vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
break; break;
} }
case _obj::redirect : case _obj::_redirect :
{ {
redirect_t* t = dynamic_cast<redirect_t*>(o); redirect* t = dynamic_cast<redirect*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) );
vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op))); vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op)));
vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target))); vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target)));
vec.push_back(std::make_pair(quote_string("here_document"), gen_json_struc(t->here_document)));
break; break;
} }
case _obj::arg : case _obj::_arg :
{ {
arg_t* t = dynamic_cast<arg_t*>(o); arg* t = dynamic_cast<arg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) );
vec.push_back(std::make_pair(quote_string("forcequoted"), boolstring(t->forcequoted)));
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->sa) for(auto it: t->sa)
tvec.push_back(gen_json_struc(it)); tvec.push_back(gen_json_struc(it));
vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec)));
break; break;
} }
case _obj::arglist : case _obj::_arglist :
{ {
arglist_t* t = dynamic_cast<arglist_t*>(o); arglist* t = dynamic_cast<arglist*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->args) for(auto it: t->args)
@ -676,9 +567,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec)));
break; break;
} }
case _obj::pipeline : case _obj::_pipeline :
{ {
pipeline_t* t = dynamic_cast<pipeline_t*>(o); pipeline* t = dynamic_cast<pipeline*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) );
vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) ); vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
@ -687,9 +578,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec))); vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec)));
break; break;
} }
case _obj::condlist : case _obj::_condlist :
{ {
condlist_t* t = dynamic_cast<condlist_t*>(o); condlist* t = dynamic_cast<condlist*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) );
vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) ); vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
@ -705,9 +596,9 @@ std::string gen_json_struc(_obj* o)
vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec))); vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec)));
break; break;
} }
case _obj::list : case _obj::_list :
{ {
list_t* t = dynamic_cast<list_t*>(o); list* t = dynamic_cast<list*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) );
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->cls) for(auto it: t->cls)
@ -717,7 +608,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_subshell : case _obj::block_subshell :
{ {
subshell_t* t = dynamic_cast<subshell_t*>(o); subshell* t = dynamic_cast<subshell*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) );
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst))); vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
@ -731,7 +622,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_brace : case _obj::block_brace :
{ {
brace_t* t = dynamic_cast<brace_t*>(o); brace* t = dynamic_cast<brace*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) );
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst))); vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
@ -760,7 +651,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_function : case _obj::block_function :
{ {
function_t* t = dynamic_cast<function_t*>(o); function* t = dynamic_cast<function*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) );
vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) ); vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) );
@ -775,7 +666,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_cmd : case _obj::block_cmd :
{ {
cmd_t* t = dynamic_cast<cmd_t*>(o); cmd* t = dynamic_cast<cmd*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) );
vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args))); vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args)));
@ -790,15 +681,6 @@ std::string gen_json_struc(_obj* o)
aa.push_back(gen_json(ttvec)); aa.push_back(gen_json(ttvec));
} }
vec.push_back(std::make_pair( quote_string("var_assigns"), gen_json(aa))); vec.push_back(std::make_pair( quote_string("var_assigns"), gen_json(aa)));
std::vector<std::string> bb;
for(auto it: t->cmd_var_assigns)
{
std::vector<std::pair<std::string,std::string>> ttvec;
ttvec.push_back( std::make_pair(quote_string("var"), gen_json_struc(it.first)) );
ttvec.push_back( std::make_pair(quote_string("value"), gen_json_struc(it.second)) );
bb.push_back(gen_json(ttvec));
}
vec.push_back(std::make_pair( quote_string("cmd_var_assigns"), gen_json(bb)));
std::vector<std::string> tvec; std::vector<std::string> tvec;
for(auto it: t->redirs) for(auto it: t->redirs)
@ -809,7 +691,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_case : case _obj::block_case :
{ {
case_t* t = dynamic_cast<case_t*>(o); case_block* t = dynamic_cast<case_block*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) );
vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg))); vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg)));
@ -838,7 +720,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_if : case _obj::block_if :
{ {
if_t* t = dynamic_cast<if_t*>(o); if_block* t = dynamic_cast<if_block*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) );
std::vector<std::string> condblocks; std::vector<std::string> condblocks;
@ -863,7 +745,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_for : case _obj::block_for :
{ {
for_t* t = dynamic_cast<for_t*>(o); for_block* t = dynamic_cast<for_block*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var))); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var)));
vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter))); vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter)));
@ -878,7 +760,7 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::block_while : case _obj::block_while :
{ {
while_t* t = dynamic_cast<while_t*>(o); while_block* t = dynamic_cast<while_block*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) );
vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) ); vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) );
vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) ); vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) );
@ -892,21 +774,21 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::subarg_variable : case _obj::subarg_variable :
{ {
subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o); variable_subarg* t = dynamic_cast<variable_subarg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) ); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
break; break;
} }
case _obj::subarg_subshell : case _obj::subarg_subshell :
{ {
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o); subshell_subarg* t = dynamic_cast<subshell_subarg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
break; break;
} }
case _obj::subarg_procsub : case _obj::subarg_procsub :
{ {
subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o); procsub_subarg* t = dynamic_cast<procsub_subarg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) );
vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) ); vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
@ -914,35 +796,35 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::subarg_arithmetic : case _obj::subarg_arithmetic :
{ {
subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o); arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) );
vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) ); vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) );
break; break;
} }
case _obj::subarg_string : case _obj::subarg_string :
{ {
subarg_string_t* t = dynamic_cast<subarg_string_t*>(o); string_subarg* t = dynamic_cast<string_subarg*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) );
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
break; break;
} }
case _obj::arithmetic_variable : case _obj::arithmetic_variable :
{ {
arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o); variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) );
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) ); vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
break; break;
} }
case _obj::arithmetic_subshell : case _obj::arithmetic_subshell :
{ {
arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o); subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) );
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) ); vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
break; break;
} }
case _obj::arithmetic_operation : case _obj::arithmetic_operation :
{ {
arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o); operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) );
vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) ); vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) );
vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) ); vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) );
@ -950,14 +832,14 @@ std::string gen_json_struc(_obj* o)
} }
case _obj::arithmetic_parenthesis : case _obj::arithmetic_parenthesis :
{ {
arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o); parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) );
vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) );
break; break;
} }
case _obj::arithmetic_number : case _obj::arithmetic_number :
{ {
arithmetic_number_t* t = dynamic_cast<arithmetic_number_t*>(o); number_arithmetic* t = dynamic_cast<number_arithmetic*>(o);
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) ); vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) );
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) ); vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
break; break;

View file

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

View file

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

View file

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

View file

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

View file

@ -45,6 +45,14 @@ std::string dirname(std::string const& in)
return "."; return ".";
} }
bool is_among(std::string const& in, std::vector<std::string> const& values)
{
for(auto it: values)
if(in == it)
return true;
return false;
}
std::vector<std::string> split(std::string const& in, const char* splitters) std::vector<std::string> split(std::string const& in, const char* splitters)
{ {
uint32_t i=0,j=0; uint32_t i=0,j=0;
@ -196,19 +204,6 @@ std::string stringReplace(std::string subject, const std::string& search, const
return subject; return subject;
} }
std::string escape_chars(std::string subject, const char* chars)
{
for(size_t i=0; i<subject.size(); i++)
{
if(is_in(subject[i], chars))
{
subject.insert(subject.begin()+i, '\\');
i++;
}
}
return subject;
}
std::string repeatString(std::string const& str, uint32_t n) std::string repeatString(std::string const& str, uint32_t n)
{ {
std::string ret; std::string ret;

View file

@ -1,47 +0,0 @@
#!/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)

View file

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

View file

@ -1,38 +0,0 @@
#!/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[@]}

View file

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

View file

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

View file

@ -1,8 +0,0 @@
#!/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}}

View file

@ -1,17 +0,0 @@
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

View file

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

View file

@ -1,22 +0,0 @@
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

View file

@ -1,50 +0,0 @@
#!/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)

View file

@ -1,78 +0,0 @@
#!/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"

View file

@ -1,12 +0,0 @@
#!/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

View file

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

View file

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

View file

@ -1,66 +0,0 @@
#!/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

View file

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

View file

@ -1,18 +0,0 @@
#!/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

View file

@ -1,48 +0,0 @@
#!/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

View file

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

View file

@ -1,9 +0,0 @@
#!/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

View file

@ -1,15 +0,0 @@
#!/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*}

View file

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

View file

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

View file

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

View file

@ -1,9 +0,0 @@
#!/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

View file

@ -1,10 +0,0 @@
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

View file

@ -1,31 +0,0 @@
#!/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

View file

@ -1,23 +0,0 @@
#!/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