Compare commits
116 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f74c97fc7f | ||
|
|
6453b44b00 | ||
|
|
f93447e7dc | ||
|
|
0903cf41a1 | ||
|
|
8f0fd6f956 | ||
|
|
bce1d4b455 | ||
|
|
fe7e6cdb52 | ||
|
|
b2c5aeea02 | ||
|
|
d41ec0e3c6 | ||
|
|
2024152dc6 | ||
|
|
29f0fd91ad | ||
|
|
32b19a12fd | ||
|
|
cdd03f28ac | ||
|
|
8a64d4e207 | ||
|
|
84ac0fa0ff | ||
|
|
97da108d1a | ||
|
|
d10be4116a | ||
|
|
0d56e6099d | ||
|
|
0eb98c8c13 | ||
|
|
78a768e98e | ||
|
|
44c03ca0be | ||
|
|
fab144947a | ||
|
|
eac178e07a | ||
|
|
db3994f6d2 | ||
|
|
9dc7c12448 | ||
|
|
39cc1da707 | ||
|
|
a9e6b27ace | ||
|
|
9a3086fc06 | ||
|
|
0e9aa3b023 | ||
|
|
92d4caf5c0 | ||
|
|
6eb164fd58 | ||
|
|
89160324cd | ||
|
|
e80ca9fb4c | ||
|
|
cdf4ca5b85 | ||
|
|
0b46581b22 | ||
|
|
2d0041e1ff | ||
|
|
19fb7e8eac | ||
|
|
abce171e94 | ||
|
|
92d5f83b2f | ||
|
|
516fbd5a01 | ||
|
|
04ef171515 | ||
|
|
04abba0dfd | ||
|
|
9d034673ec | ||
|
|
65dc4d8c40 | ||
|
|
23a8c12bca | ||
|
|
6e64ed64c4 | ||
|
|
f27bb49626 | ||
|
|
4ff253a364 | ||
|
|
536168eee4 | ||
|
|
3562cb77b2 | ||
|
|
20e47ab620 | ||
|
|
22ab42da08 | ||
|
|
ee0435101b | ||
|
|
d90d07635d | ||
|
|
733e6a572d | ||
|
|
74aa26d935 | ||
|
|
4b8e3874e1 | ||
|
|
cb6cf4a1d7 | ||
|
|
34d5c059e0 | ||
|
|
251e70e869 | ||
|
|
f8b5e04423 | ||
|
|
8c63b9a35e | ||
|
|
4c984bdc39 | ||
|
|
56bd8a3db7 | ||
|
|
66b4aaa153 | ||
|
|
982e86cc87 | ||
|
|
c5f505462f | ||
|
|
5a34d8c39e | ||
|
|
6e87d180c2 | ||
|
|
aef06f4932 | ||
|
|
be4c043a08 | ||
|
|
3af1fc57fc | ||
|
|
767302dd56 | ||
|
|
0be14815fa | ||
|
|
40aee8e3cf | ||
|
|
e7d868de9e | ||
|
|
38845e8652 | ||
|
|
c6c224bd12 | ||
|
|
d8b3041e85 | ||
|
|
8c3d693182 | ||
|
|
0e6fc1262d | ||
|
|
3dc60ff7e3 | ||
|
|
579a806c64 | ||
|
|
d461f625e8 | ||
|
|
f80594d292 | ||
|
|
ca2839ec9c | ||
|
|
e5d0cf819d | ||
|
|
bc846bcc56 | ||
|
|
f851650c15 | ||
|
|
56ed26ed96 | ||
|
|
5d8ea952a2 | ||
|
|
052b2b92cb | ||
|
|
76779cd32d | ||
|
|
3429a398cf | ||
|
|
a07d0d7a93 | ||
|
|
bb515636ff | ||
|
|
4b16fa029f | ||
|
|
f4d417406b | ||
|
|
f9a3efce9a | ||
|
|
8b6a576713 | ||
|
|
9918bb61ba | ||
|
|
05723fe994 | ||
|
|
9ddf23dd4b | ||
|
|
6b8f7241bb | ||
|
|
09186df7b1 | ||
|
|
15ac04f505 | ||
|
|
3e21098d95 | ||
|
|
064c37b4ee | ||
|
|
86a4d4a118 | ||
|
|
7379eaf180 | ||
|
|
c0f5e4ba27 | ||
|
|
bc215fc994 | ||
|
|
58b95c45e7 | ||
|
|
a02edd6c2c | ||
|
|
1f75f18fba | ||
|
|
af5d276ff0 |
60 changed files with 4914 additions and 2358 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,10 +1,8 @@
|
||||||
/obj
|
/obj
|
||||||
/test
|
|
||||||
/run-tests.sh
|
|
||||||
/Zmakefile
|
/Zmakefile
|
||||||
/TODO
|
TODO
|
||||||
/lxsh
|
/lxsh
|
||||||
/gmon.out
|
gmon.out
|
||||||
/profiling/*
|
/profiling/*
|
||||||
/profiling.*
|
/profiling.*
|
||||||
/include/g_*
|
/include/g_*
|
||||||
|
|
|
||||||
68
Makefile
68
Makefile
|
|
@ -14,65 +14,83 @@ LDFLAGS = -lpthread
|
||||||
# compiler
|
# compiler
|
||||||
CC=g++
|
CC=g++
|
||||||
# compiler flags
|
# compiler flags
|
||||||
CXXFLAGS= -I$(IDIR) -Wall -pedantic -std=c++20
|
CXXFLAGS= -I$(IDIR) -Wall -std=c++20
|
||||||
ifeq ($(DEBUG),true)
|
ifeq ($(DEBUG),true)
|
||||||
# debugging flags
|
# debugging flags
|
||||||
CC=clang++
|
CXXFLAGS += -g -D DEBUG_MODE
|
||||||
CXXFLAGS += -g -pg -D NO_PARSE_CATCH
|
RODIR = $(ODIR)/debug
|
||||||
else
|
else
|
||||||
# release flags
|
# release flags
|
||||||
CXXFLAGS += -Ofast
|
CXXFLAGS += -Ofast
|
||||||
|
RODIR = $(ODIR)/release
|
||||||
|
endif
|
||||||
|
ifeq ($(STATIC),true)
|
||||||
|
# static links
|
||||||
|
LDFLAGS += -l:libztd.a
|
||||||
|
else
|
||||||
|
# dynamic links
|
||||||
|
LDFLAGS += -lztd
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifeq ($(PROFILE),true)
|
||||||
|
CXXFLAGS += -pg
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(RELEASE), true)
|
ifneq ($(RELEASE), true)
|
||||||
VSUFFIX=-dev-$(SHA_SHORT)
|
VSUFFIX=-dev-$(SHA_SHORT)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(STATIC),true)
|
|
||||||
# static links
|
|
||||||
LDFLAGS += -l:libztd.a
|
|
||||||
else
|
|
||||||
# dynamic links
|
|
||||||
LDFLAGS += -lztd
|
|
||||||
endif
|
|
||||||
|
|
||||||
## END CONFIG ##
|
## END CONFIG ##
|
||||||
|
|
||||||
|
|
||||||
$(shell ./generate_version.sh)
|
$(shell ./generate_version.sh)
|
||||||
$(shell ./generate_shellcode.sh)
|
$(shell ./generate_shellcode.sh)
|
||||||
$(shell mkdir -p $(ODIR))
|
|
||||||
|
$(shell mkdir -p $(RODIR))
|
||||||
$(shell mkdir -p $(BINDIR))
|
$(shell mkdir -p $(BINDIR))
|
||||||
|
|
||||||
# automatically find .h and .hpp
|
# automatically find .h and .hpp
|
||||||
DEPS = $(shell find $(IDIR) -type f -regex '.*\.hp?p?' ! -name 'g_version.h' ! -name 'g_shellcode.h')
|
DEPS = $(shell find $(IDIR) -type f -regex '.*\.hp?p?')
|
||||||
# automatically find .c and .cpp and make the corresponding .o rule
|
# automatically find .c and .cpp and make the corresponding .o rule
|
||||||
OBJ = $(shell find $(SRCDIR) -type f -regex '.*\.cp?p?' | sed 's|\.cpp|.o|g;s|\.c|.o|g;s|^$(SRCDIR)/|$(ODIR)/|g')
|
OBJ = $(shell find $(SRCDIR) -type f -regex '.*\.cp?p?' | sed 's|\.cpp|.o|g;s|\.c|.o|g;s|^$(SRCDIR)/|$(RODIR)/|g')
|
||||||
|
|
||||||
build: lxsh $(OBJ) $(DEPS)
|
build: $(BINDIR)/$(NAME)
|
||||||
|
|
||||||
$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
|
# specific files for autogenerated headers
|
||||||
|
$(OBJDIR)/options.o: $(SRCDIR)/options.cpp $(DEPS) $(IDIR)/g_version.h
|
||||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
$(OBJDIR)/shellcode.o: $(SRCDIR)/shellcode.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
||||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(ODIR)/options.o: $(SRCDIR)/options.cpp $(DEPS) $(IDIR)/g_version.h
|
$(OBJDIR)/debashify.o: $(SRCDIR)/debashify.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
||||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(ODIR)/shellcode.o: $(SRCDIR)/shellcode.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
# generic files
|
||||||
|
|
||||||
|
$(RODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
|
||||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(ODIR)/debashify.o: $(SRCDIR)/debashify.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
$(RODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
lxsh: $(OBJ)
|
|
||||||
|
$(BINDIR)/$(NAME): $(OBJ)
|
||||||
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test: $(BINDIR)/$(NAME)
|
test: $(BINDIR)/$(NAME)
|
||||||
$(BINDIR)/$(NAME)
|
$(BINDIR)/$(NAME)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(ODIR)/*.o gmon.out
|
rm $(ODIR)/*/*.o
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
61
README.md
61
README.md
|
|
@ -8,20 +8,20 @@ Extended shell linker for linking, processing and minifying shell code
|
||||||
|
|
||||||
### zpkg
|
### zpkg
|
||||||
|
|
||||||
Available from the `zpkg` repository:
|
Available from the [zpkg](https://github.com/zawwz/zpkg) repository:
|
||||||
```shell
|
```shell
|
||||||
wget -qO- https://zpkg.zawz.net/install.sh | sh
|
wget -qO- https://zpkg.zawz.net/install.sh | sh
|
||||||
zpkg install lxsh
|
zpkg install lxsh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Binary
|
### Binary amd64
|
||||||
|
|
||||||
Download the `lxsh-linux-amd64.tar.gz` archive, extract it,
|
Download the `lxsh-linux-amd64.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.0.0/lxsh-linux-amd64.tar.xz
|
wget https://github.com/zawwz/lxsh/releases/download/v1.3.0/lxsh-linux-amd64.tar.gz
|
||||||
tar -xvf lxsh.tar.gz
|
tar -xvf lxsh-linux-amd64.tar.gz
|
||||||
sudo mv lxsh /usr/local/bin
|
sudo mv lxsh /usr/local/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -45,6 +45,22 @@ 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.
|
||||||
|
|
@ -58,6 +74,8 @@ use `--exclude-fct` to exclude functions from being minified.
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
## Debashify
|
## Debashify
|
||||||
|
|
||||||
Some bash specific features can be translated into POSIX shell code.
|
Some bash specific features can be translated into POSIX shell code.
|
||||||
|
|
@ -69,6 +87,9 @@ 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
|
||||||
|
|
||||||
|
|
@ -116,7 +137,28 @@ these features will continue working with undesired behavior.
|
||||||
|
|
||||||
> To avoid this, make sure to never access incorrect values
|
> To avoid this, make sure to never access incorrect values
|
||||||
|
|
||||||
Array argument with `[@]` does not work with spaces, tabs and newlines in values.
|
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
|
||||||
|
|
||||||
|
If you use the `#!/usr/bin/lxsh` shebang, you can use special lxsh-defined commands.
|
||||||
|
To list such commands, see `lxsh --help-extend-fcts`
|
||||||
|
|
||||||
|
## String processors
|
||||||
|
|
||||||
|
You can use prefixes in singlequote strings to apply processing to the string contents. <br>
|
||||||
|
To use string processors, prefix the string content with a line in the form of `#<PROCESSOR>`.
|
||||||
|
Example:
|
||||||
|
```shell
|
||||||
|
sh -c '#LXSH_PARSE_MINIFY
|
||||||
|
printf "%s\n" "Hello world!"'
|
||||||
|
```
|
||||||
|
|
||||||
|
As of now only the processor `LXSH_PARSE_MINIFY` is implemented, but more may come later
|
||||||
|
|
||||||
## Other features
|
## Other features
|
||||||
|
|
||||||
|
|
@ -133,11 +175,8 @@ Directly execute an extended lxsh script with either
|
||||||
- `-e` option
|
- `-e` option
|
||||||
- shebang is lxsh
|
- shebang is lxsh
|
||||||
|
|
||||||
> Direct execution introduces direct dependency on lxsh and code generation overhead,
|
> Direct execution introduces direct dependency on lxsh and code parsing overhead,
|
||||||
> therefore it should be avoided outside of development use.
|
> therefore it should be avoided in production environments.
|
||||||
> This may be optimized in a later version
|
|
||||||
|
|
||||||
> There are some issues with direct execution as of now
|
|
||||||
|
|
||||||
### Variable/Function/command listing
|
### Variable/Function/command listing
|
||||||
|
|
||||||
|
|
@ -151,7 +190,7 @@ Depends on [ztd](https://github.com/zawwz/ztd)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Use `make -j11` to build.<br>
|
Use `make -j` to build.<br>
|
||||||
You can use environment variables to alter some aspects:
|
You can use environment variables to alter some aspects:
|
||||||
- DEBUG: when set to `true` will generate a debug binary with profiling
|
- DEBUG: when set to `true` will generate a debug binary with profiling
|
||||||
- RELEASE: when set to `true`, the version string will be generated for release format
|
- RELEASE: when set to `true`, the version string will be generated for release format
|
||||||
|
|
|
||||||
3
completion/lxsh.bash
Normal file
3
completion/lxsh.bash
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#/usr/bin/env bash
|
||||||
|
|
||||||
|
complete -F _longopt lxsh
|
||||||
|
|
@ -6,13 +6,13 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
typedef struct debashify_params {
|
struct debashify_params {
|
||||||
std::set<std::string> required_fcts;
|
std::set<std::string> required_fcts;
|
||||||
void require_fct(std::string const& in) { required_fcts.insert(in); }
|
void require_fct(std::string const& in) { required_fcts.insert(in); }
|
||||||
// map of detected arrays
|
// map of detected arrays
|
||||||
// bool value: is associative
|
// bool value: is associative
|
||||||
std::map<std::string,bool> arrays;
|
std::map<std::string,bool> arrays;
|
||||||
} debashify_params;
|
};
|
||||||
|
|
||||||
bool r_debashify(_obj* o, debashify_params* params);
|
bool r_debashify(_obj* o, debashify_params* params);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef ERRCODES_H
|
#ifndef ERRCODES_H
|
||||||
#define ERRCODES_H
|
#define ERRCODES_H
|
||||||
|
|
||||||
#define ERR_HELP 1001
|
#define ERR_HELP 101
|
||||||
#define ERR_OPT 1002
|
#define ERR_OPT 102
|
||||||
#define ERR_PARSE 1003
|
#define ERR_PARSE 103
|
||||||
#define ERR_RUNTIME 1004
|
#define ERR_RUNTIME 104
|
||||||
|
|
||||||
#endif //ERRCODES_H
|
#endif //ERRCODES_H
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
#define EXEC_HPP
|
#define EXEC_HPP
|
||||||
|
|
||||||
#include "options.hpp"
|
#include "options.hpp"
|
||||||
|
#include "parse.hpp"
|
||||||
|
|
||||||
|
|
||||||
void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& filename="");
|
void parse_exec(FILE* fd, parse_context ct);
|
||||||
inline void parse_exec(FILE* fd, std::string const& in, std::string const& filename="") { parse_exec(fd, in.c_str(), in.size(), filename); }
|
|
||||||
|
|
||||||
int exec_process(std::string const& runtime, std::vector<std::string> const& args, std::string const& filecontents, std::string const& file);
|
int exec_process(std::string const& runtime, std::vector<std::string> const& args, parse_context ct);
|
||||||
|
|
||||||
#endif //EXEC_HPP
|
#endif //EXEC_HPP
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,22 @@
|
||||||
#define MINIFY_HPP
|
#define MINIFY_HPP
|
||||||
|
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
#include "processing.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
void minify_var(_obj* in, std::regex const& exclude);
|
std::string gen_minmap(strmap_t const& map, std::string const& prefix);
|
||||||
void minify_fct(_obj* in, std::regex const& exclude);
|
void read_minmap(std::string const& filepath, strmap_t* varmap, strmap_t* fctmap);
|
||||||
|
|
||||||
|
bool r_replace_fct(_obj* in, strmap_t* fctmap);
|
||||||
|
bool r_replace_var(_obj* in, strmap_t* varmap);
|
||||||
|
|
||||||
|
strmap_t minify_var(_obj* in, std::regex const& exclude);
|
||||||
|
strmap_t minify_fct(_obj* in, std::regex const& exclude);
|
||||||
|
|
||||||
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_quotes(_obj* in);
|
void minify_generic(_obj* in);
|
||||||
|
|
||||||
#endif //MINIFY_HPP
|
#endif //MINIFY_HPP
|
||||||
|
|
|
||||||
|
|
@ -6,80 +6,123 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
#include <ztd/filedat.hpp>
|
#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 COMMAND_SEPARATOR "\n;"
|
#define COMMAND_SEPARATOR "\n;"
|
||||||
#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 "$\\`"
|
||||||
|
#define ARG_OPTIMIZE_MANIP "$\\`}"
|
||||||
|
#define ARG_OPTIMIZE_DEFARR "$\\`)"
|
||||||
|
#define ARG_OPTIMIZE_BASHTEST "$\\`] \t\n"
|
||||||
|
#define ARG_OPTIMIZE_ARG "$\\` \t\n;()&|<>\"'"
|
||||||
|
#define ARG_OPTIMIZE_ARRAY "$\\`\t\n&|}[]\"'"
|
||||||
|
#define ARG_OPTIMIZE_ALL "$\\` \t\n;#()&|<>}]\"'"
|
||||||
|
|
||||||
// macros
|
// structs
|
||||||
#define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i)
|
|
||||||
|
struct list_parse_options {
|
||||||
|
char end_char=0;
|
||||||
|
bool word_mode=false;
|
||||||
|
std::vector<std::string> end_words={};
|
||||||
|
const char* expecting=NULL;
|
||||||
|
};
|
||||||
|
|
||||||
// globals
|
// globals
|
||||||
|
extern const std::set<std::string> all_reserved_words;
|
||||||
extern bool g_bash;
|
extern const std::set<std::string> posix_cmdvar;
|
||||||
|
extern const std::set<std::string> bash_cmdvar;
|
||||||
extern const std::vector<std::string> posix_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);
|
||||||
|
|
||||||
shmain* parse_text(const char* in, uint32_t size, std::string const& filename="");
|
std::pair<shmain*, parse_context> parse_text(parse_context context);
|
||||||
inline shmain* parse_text(std::string const& in, std::string const& filename="") { return parse_text(in.c_str(), in.size(), filename); }
|
std::pair<shmain*, parse_context> parse_text(std::string const& in, std::string const& filename="");
|
||||||
inline shmain* parse(std::string const& file) { return parse_text(import_file(file), file); }
|
inline std::pair<shmain*, parse_context> parse(std::string const& file) { return parse_text(import_file(file), file); }
|
||||||
|
|
||||||
|
// tools
|
||||||
|
|
||||||
|
parse_context make_context(std::string const& in, std::string const& filename="", bool bash=false);
|
||||||
|
parse_context make_context(parse_context ctx, std::string const& in="", std::string const& filename="", bool bash=false);
|
||||||
|
parse_context make_context(parse_context ctx, uint64_t i);
|
||||||
|
parse_context operator+(parse_context ctx, int64_t a);
|
||||||
|
parse_context operator-(parse_context ctx, int64_t a);
|
||||||
|
|
||||||
|
// error handlers
|
||||||
|
void parse_error(std::string const& message, parse_context& ctx);
|
||||||
|
void parse_error(std::string const& message, parse_context& ctx, uint64_t i);
|
||||||
|
|
||||||
// ** unit parsers ** //
|
// ** unit parsers ** //
|
||||||
|
|
||||||
/* util parsers */
|
/* util parsers */
|
||||||
bool word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set=NULL);
|
uint32_t word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set=NULL);
|
||||||
std::pair<std::string,uint32_t> get_word(const char* in, uint32_t size, uint32_t start, const char* end_set);
|
inline bool word_eq(const char* word, parse_context const& ct, const char* end_set=NULL) {
|
||||||
|
return word_eq(word, ct.data, ct.size, ct.i, end_set);
|
||||||
|
}
|
||||||
|
std::pair<std::string,uint32_t> get_word(parse_context ct, const char* end_set);
|
||||||
uint32_t skip_chars(const char* in, uint32_t size, uint32_t start, const char* set);
|
uint32_t skip_chars(const char* in, uint32_t size, uint32_t start, const char* set);
|
||||||
|
inline uint32_t skip_chars(parse_context const& ct, const char* set) {
|
||||||
|
return skip_chars(ct.data, ct.size, ct.i, set);
|
||||||
|
}
|
||||||
uint32_t skip_until(const char* in, uint32_t size, uint32_t start, const char* set);
|
uint32_t skip_until(const char* in, uint32_t size, uint32_t start, const char* set);
|
||||||
|
inline uint32_t skip_until(parse_context const& ct, const char* set) {
|
||||||
|
return skip_until(ct.data, ct.size, ct.i, set);
|
||||||
|
}
|
||||||
uint32_t skip_unread(const char* in, uint32_t size, uint32_t start);
|
uint32_t skip_unread(const char* in, uint32_t size, uint32_t start);
|
||||||
|
inline uint32_t skip_unread(parse_context const& ct) {
|
||||||
|
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::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, char end_c, const char* expecting=NULL);
|
std::tuple<list_t*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
|
||||||
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
|
|
||||||
std::tuple<list*, uint32_t, std::string> parse_list_until(const char* in, uint32_t size, uint32_t start, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
|
||||||
// name
|
// name
|
||||||
std::pair<variable*, uint32_t> parse_var(const char* in, uint32_t size, uint32_t start, bool specialvars=true, bool array=false);
|
std::pair<variable_t*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
|
||||||
|
|
||||||
// subarg parsers
|
// subarg parsers
|
||||||
std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start);
|
std::pair<arithmetic_t*, parse_context> parse_arithmetic(parse_context ct);
|
||||||
std::pair<variable*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start);
|
std::pair<variable_t*, parse_context> parse_manipulation(parse_context ct);
|
||||||
// arg parser
|
// arg parser
|
||||||
std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true);
|
std::pair<arg_t*, parse_context> parse_arg(parse_context ct, const char* end=ARG_END, const char* unexpected=ARGLIST_END, bool doquote=true, const char* optimize=ARG_OPTIMIZE_ARG);
|
||||||
// redirect parser
|
// redirect parser
|
||||||
std::pair<redirect*, uint32_t> parse_redirect(const char* in, uint32_t size, uint32_t start);
|
std::pair<redirect_t*, parse_context> parse_redirect(parse_context ct);
|
||||||
// arglist parser
|
// arglist parser
|
||||||
std::pair<arglist*, uint32_t> parse_arglist(const char* in, uint32_t size, uint32_t start, bool hard_error=false, std::vector<redirect*>* redirs=nullptr);
|
std::pair<arglist_t*, parse_context> parse_arglist(parse_context ct, bool hard_error=false, std::vector<redirect_t*>* redirs=nullptr, bool stop_on_brace=false);
|
||||||
// block parsers
|
// block parsers
|
||||||
std::pair<block*, uint32_t> parse_block(const char* in, uint32_t size, uint32_t start);
|
std::pair<block_t*, parse_context> parse_block(parse_context ct);
|
||||||
std::pair<cmd*, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t start);
|
std::pair<cmd_t*, parse_context> parse_cmd(parse_context ct);
|
||||||
std::pair<function*, uint32_t> parse_function(const char* in, uint32_t size, uint32_t start, const char* after="()");
|
std::pair<function_t*, parse_context> parse_function(parse_context ct, const char* after="()");
|
||||||
std::pair<subshell*, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_t start);
|
std::pair<subshell_t*, parse_context> parse_subshell(parse_context ct);
|
||||||
std::pair<brace*, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t start);
|
std::pair<brace_t*, parse_context> parse_brace(parse_context ct);
|
||||||
std::pair<case_block*, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start);
|
std::pair<case_t*, parse_context> parse_case(parse_context ct);
|
||||||
std::pair<if_block*, uint32_t> parse_if(const char* in, uint32_t size, uint32_t start);
|
std::pair<if_t*, parse_context> parse_if(parse_context ct);
|
||||||
std::pair<for_block*, uint32_t> parse_for(const char* in, uint32_t size, uint32_t start);
|
std::pair<for_t*, parse_context> parse_for(parse_context ct);
|
||||||
std::pair<while_block*, uint32_t> parse_while(const char* in, uint32_t size, uint32_t start);
|
std::pair<while_t*, parse_context> parse_while(parse_context ct);
|
||||||
// pipeline parser
|
// pipeline parser
|
||||||
std::pair<pipeline*, uint32_t> parse_pipeline(const char* in, uint32_t size, uint32_t start);
|
std::pair<pipeline_t*, parse_context> parse_pipeline(parse_context ct);
|
||||||
// condlist parser
|
// condlist parser
|
||||||
std::pair<condlist*, uint32_t> parse_condlist(const char* in, uint32_t size, uint32_t start);
|
std::pair<condlist_t*, parse_context> parse_condlist(parse_context ct);
|
||||||
|
|
||||||
#endif //PARSE_HPP
|
#endif //PARSE_HPP
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR"
|
#define RESERVED_VARIABLES "HOME", "PATH", "SHELL", "PWD", "OPTIND", "OPTARG", "LC_.*", "LANG", "TERM", "RANDOM", "TMPDIR", "IFS"
|
||||||
|
|
||||||
// types
|
// types
|
||||||
typedef std::map<std::string,uint32_t> countmap_t;
|
typedef std::map<std::string,uint32_t> countmap_t;
|
||||||
|
|
@ -29,8 +29,11 @@ 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;
|
||||||
|
|
||||||
/** map get functions (optimizations) **/
|
// 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) **/
|
||||||
|
|
||||||
// rescans
|
// rescans
|
||||||
void require_rescan_all();
|
void require_rescan_all();
|
||||||
|
|
@ -42,9 +45,13 @@ 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);
|
||||||
|
|
@ -53,7 +60,7 @@ std::regex fct_exclude_regex(std::string const& in);
|
||||||
// varnames
|
// varnames
|
||||||
bool is_varname(std::string const& in);
|
bool is_varname(std::string const& in);
|
||||||
std::string get_varname(std::string const& in);
|
std::string get_varname(std::string const& in);
|
||||||
std::string get_varname(arg* in);
|
std::string get_varname(arg_t* in);
|
||||||
|
|
||||||
// list objects
|
// list objects
|
||||||
void list_map(countmap_t const& map);
|
void list_map(countmap_t const& map);
|
||||||
|
|
@ -64,16 +71,24 @@ 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);
|
||||||
|
|
||||||
#endif //PROCESSING_HPP
|
#endif //PROCESSING_HPP
|
||||||
|
|
|
||||||
|
|
@ -19,67 +19,58 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
// recursive calls
|
// recursive calls
|
||||||
switch(o->type)
|
switch(o->type)
|
||||||
{
|
{
|
||||||
case _obj::_variable :
|
case _obj::variable :
|
||||||
{
|
{
|
||||||
variable* t = dynamic_cast<variable*>(o);
|
variable_t* t = dynamic_cast<variable_t*>(o);
|
||||||
recurse(fct, t->index, args...);
|
recurse(fct, t->index, args...);
|
||||||
recurse(fct, t->manip, args...);
|
recurse(fct, t->manip, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_redirect :
|
case _obj::redirect :
|
||||||
{
|
{
|
||||||
redirect* t = dynamic_cast<redirect*>(o);
|
redirect_t* t = dynamic_cast<redirect_t*>(o);
|
||||||
recurse(fct, t->target, args...);
|
recurse(fct, t->target, args...);
|
||||||
|
recurse(fct, t->here_document, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_arg :
|
case _obj::arg :
|
||||||
{
|
{
|
||||||
arg* t = dynamic_cast<arg*>(o);
|
arg_t* t = dynamic_cast<arg_t*>(o);
|
||||||
for(auto it: t->sa)
|
for(auto it: t->sa)
|
||||||
{
|
|
||||||
recurse(fct, it, args...);
|
recurse(fct, it, args...);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_arglist :
|
case _obj::arglist :
|
||||||
{
|
{
|
||||||
arglist* t = dynamic_cast<arglist*>(o);
|
arglist_t* t = dynamic_cast<arglist_t*>(o);
|
||||||
for(auto it: t->args)
|
for(auto it: t->args)
|
||||||
{
|
|
||||||
recurse(fct, it, args...);
|
recurse(fct, it, args...);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_pipeline :
|
case _obj::pipeline :
|
||||||
{
|
{
|
||||||
pipeline* t = dynamic_cast<pipeline*>(o);
|
pipeline_t* t = dynamic_cast<pipeline_t*>(o);
|
||||||
for(auto it: t->cmds)
|
for(auto it: t->cmds)
|
||||||
{
|
|
||||||
recurse(fct, it, args...);
|
recurse(fct, it, args...);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_condlist :
|
case _obj::condlist :
|
||||||
{
|
{
|
||||||
condlist* t = dynamic_cast<condlist*>(o);
|
condlist_t* t = dynamic_cast<condlist_t*>(o);
|
||||||
for(auto it: t->pls)
|
for(auto it: t->pls)
|
||||||
{
|
|
||||||
recurse(fct, it, args...);
|
recurse(fct, it, args...);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_list :
|
case _obj::list :
|
||||||
{
|
{
|
||||||
list* t = dynamic_cast<list*>(o);
|
list_t* t = dynamic_cast<list_t*>(o);
|
||||||
for(auto it: t->cls)
|
for(auto it: t->cls)
|
||||||
{
|
|
||||||
recurse(fct, it, args...);
|
recurse(fct, it, args...);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::block_subshell :
|
case _obj::block_subshell :
|
||||||
{
|
{
|
||||||
subshell* t = dynamic_cast<subshell*>(o);
|
subshell_t* t = dynamic_cast<subshell_t*>(o);
|
||||||
recurse(fct, t->lst, args...);
|
recurse(fct, t->lst, args...);
|
||||||
|
|
||||||
for(auto it: t->redirs)
|
for(auto it: t->redirs)
|
||||||
|
|
@ -89,7 +80,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_brace :
|
case _obj::block_brace :
|
||||||
{
|
{
|
||||||
brace* t = dynamic_cast<brace*>(o);
|
brace_t* t = dynamic_cast<brace_t*>(o);
|
||||||
recurse(fct, t->lst, args...);
|
recurse(fct, t->lst, args...);
|
||||||
|
|
||||||
for(auto it: t->redirs)
|
for(auto it: t->redirs)
|
||||||
|
|
@ -109,7 +100,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_function :
|
case _obj::block_function :
|
||||||
{
|
{
|
||||||
function* t = dynamic_cast<function*>(o);
|
function_t* t = dynamic_cast<function_t*>(o);
|
||||||
recurse(fct, t->lst, args...);
|
recurse(fct, t->lst, args...);
|
||||||
|
|
||||||
for(auto it: t->redirs)
|
for(auto it: t->redirs)
|
||||||
|
|
@ -119,13 +110,18 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_cmd :
|
case _obj::block_cmd :
|
||||||
{
|
{
|
||||||
cmd* t = dynamic_cast<cmd*>(o);
|
cmd_t* t = dynamic_cast<cmd_t*>(o);
|
||||||
recurse(fct, t->args, args...);
|
recurse(fct, t->args, args...);
|
||||||
for(auto it: t->var_assigns)
|
for(auto it: t->var_assigns)
|
||||||
{
|
{
|
||||||
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...);
|
||||||
|
|
@ -134,7 +130,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_case :
|
case _obj::block_case :
|
||||||
{
|
{
|
||||||
case_block* t = dynamic_cast<case_block*>(o);
|
case_t* t = dynamic_cast<case_t*>(o);
|
||||||
// carg
|
// carg
|
||||||
recurse(fct, t->carg, args...);
|
recurse(fct, t->carg, args...);
|
||||||
// cases
|
// cases
|
||||||
|
|
@ -154,7 +150,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_if :
|
case _obj::block_if :
|
||||||
{
|
{
|
||||||
if_block* t = dynamic_cast<if_block*>(o);
|
if_t* t = dynamic_cast<if_t*>(o);
|
||||||
// ifs
|
// ifs
|
||||||
for(auto sc: t->blocks)
|
for(auto sc: t->blocks)
|
||||||
{
|
{
|
||||||
|
|
@ -173,7 +169,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_for :
|
case _obj::block_for :
|
||||||
{
|
{
|
||||||
for_block* t = dynamic_cast<for_block*>(o);
|
for_t* t = dynamic_cast<for_t*>(o);
|
||||||
// variable
|
// variable
|
||||||
recurse(fct, t->var, args...);
|
recurse(fct, t->var, args...);
|
||||||
// iterations
|
// iterations
|
||||||
|
|
@ -188,7 +184,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::block_while :
|
case _obj::block_while :
|
||||||
{
|
{
|
||||||
while_block* t = dynamic_cast<while_block*>(o);
|
while_t* t = dynamic_cast<while_t*>(o);
|
||||||
// condition
|
// condition
|
||||||
recurse(fct, t->cond, args...);
|
recurse(fct, t->cond, args...);
|
||||||
// operations
|
// operations
|
||||||
|
|
@ -201,50 +197,50 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
case _obj::subarg_variable :
|
case _obj::subarg_variable :
|
||||||
{
|
{
|
||||||
variable_subarg* t = dynamic_cast<variable_subarg*>(o);
|
subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
|
||||||
recurse(fct, t->var, args...);
|
recurse(fct, t->var, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_subshell :
|
case _obj::subarg_subshell :
|
||||||
{
|
{
|
||||||
subshell_subarg* t = dynamic_cast<subshell_subarg*>(o);
|
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
|
||||||
recurse(fct, t->sbsh, args...);
|
recurse(fct, t->sbsh, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_procsub :
|
case _obj::subarg_procsub :
|
||||||
{
|
{
|
||||||
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o);
|
subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
|
||||||
recurse(fct, t->sbsh, args...);
|
recurse(fct, t->sbsh, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_arithmetic :
|
case _obj::subarg_arithmetic :
|
||||||
{
|
{
|
||||||
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
|
subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
|
||||||
recurse(fct, t->arith, args...);
|
recurse(fct, t->arith, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_variable :
|
case _obj::arithmetic_variable :
|
||||||
{
|
{
|
||||||
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o);
|
arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
|
||||||
recurse(fct, t->var, args...);
|
recurse(fct, t->var, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_subshell :
|
case _obj::arithmetic_subshell :
|
||||||
{
|
{
|
||||||
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o);
|
arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
|
||||||
recurse(fct, t->sbsh, args...);
|
recurse(fct, t->sbsh, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_operation :
|
case _obj::arithmetic_operation :
|
||||||
{
|
{
|
||||||
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
|
arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
|
||||||
recurse(fct, t->val1, args...);
|
recurse(fct, t->val1, args...);
|
||||||
recurse(fct, t->val2, args...);
|
recurse(fct, t->val2, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_parenthesis :
|
case _obj::arithmetic_parenthesis :
|
||||||
{
|
{
|
||||||
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
|
arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
|
||||||
recurse(fct, t->val, args...);
|
recurse(fct, t->val, args...);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -253,5 +249,292 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deep copy of object structure
|
||||||
|
template<class... Args>
|
||||||
|
_obj* obj_copy(_obj* o)
|
||||||
|
{
|
||||||
|
if(o == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// recursive calls
|
||||||
|
switch(o->type)
|
||||||
|
{
|
||||||
|
case _obj::variable :
|
||||||
|
{
|
||||||
|
variable_t* t = dynamic_cast<variable_t*>(o);
|
||||||
|
variable_t* ret = new variable_t(*t);
|
||||||
|
|
||||||
|
ret->index = dynamic_cast<arg_t*>(obj_copy(t->index));
|
||||||
|
ret->manip = dynamic_cast<arg_t*>(obj_copy(t->manip));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::redirect :
|
||||||
|
{
|
||||||
|
redirect_t* t = dynamic_cast<redirect_t*>(o);
|
||||||
|
redirect_t* ret = new redirect_t(*t);
|
||||||
|
|
||||||
|
ret->target = dynamic_cast<arg_t*>(obj_copy(t->target));
|
||||||
|
ret->here_document = dynamic_cast<arg_t*>(obj_copy(t->here_document));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arg :
|
||||||
|
{
|
||||||
|
arg_t* t = dynamic_cast<arg_t*>(o);
|
||||||
|
arg_t* ret = new arg_t(*t);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->sa.size(); i++)
|
||||||
|
ret->sa[i] = dynamic_cast<subarg_t*>(obj_copy(t->sa[i]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arglist :
|
||||||
|
{
|
||||||
|
arglist_t* t = dynamic_cast<arglist_t*>(o);
|
||||||
|
arglist_t* ret = new arglist_t(*t);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->args.size(); i++)
|
||||||
|
ret->args[i] = dynamic_cast<arg_t*>(obj_copy(t->args[i]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::pipeline :
|
||||||
|
{
|
||||||
|
pipeline_t* t = dynamic_cast<pipeline_t*>(o);
|
||||||
|
pipeline_t* ret = new pipeline_t(*t);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->cmds.size(); i++)
|
||||||
|
ret->cmds[i] = dynamic_cast<block_t*>(obj_copy(t->cmds[i]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::condlist :
|
||||||
|
{
|
||||||
|
condlist_t* t = dynamic_cast<condlist_t*>(o);
|
||||||
|
condlist_t* ret = new condlist_t(*t);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->pls.size(); i++)
|
||||||
|
ret->pls[i] = dynamic_cast<pipeline_t*>(obj_copy(t->pls[i]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::list :
|
||||||
|
{
|
||||||
|
list_t* t = dynamic_cast<list_t*>(o);
|
||||||
|
list_t* ret = new list_t(*t);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->cls.size(); i++)
|
||||||
|
ret->cls[i] = dynamic_cast<condlist_t*>(obj_copy(t->cls[i]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_subshell :
|
||||||
|
{
|
||||||
|
subshell_t* t = dynamic_cast<subshell_t*>(o);
|
||||||
|
subshell_t* ret = new subshell_t(*t);
|
||||||
|
|
||||||
|
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_brace :
|
||||||
|
{
|
||||||
|
brace_t* t = dynamic_cast<brace_t*>(o);
|
||||||
|
brace_t* ret = new brace_t(*t);
|
||||||
|
|
||||||
|
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_main :
|
||||||
|
{
|
||||||
|
shmain* t = dynamic_cast<shmain*>(o);
|
||||||
|
shmain* ret = new shmain(*t);
|
||||||
|
|
||||||
|
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_function :
|
||||||
|
{
|
||||||
|
function_t* t = dynamic_cast<function_t*>(o);
|
||||||
|
function_t* ret = new function_t(*t);
|
||||||
|
|
||||||
|
ret->lst = dynamic_cast<list_t*>(obj_copy(t->lst));
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_cmd :
|
||||||
|
{
|
||||||
|
cmd_t* t = dynamic_cast<cmd_t*>(o);
|
||||||
|
cmd_t* ret = new cmd_t(*t);
|
||||||
|
|
||||||
|
ret->args = dynamic_cast<arglist_t*>(obj_copy(t->args));
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->var_assigns.size(); i++)
|
||||||
|
{
|
||||||
|
ret->var_assigns[i].first = dynamic_cast<variable_t*>(obj_copy(t->var_assigns[i].first));
|
||||||
|
ret->var_assigns[i].second = dynamic_cast<arg_t*>(obj_copy(t->var_assigns[i].second));
|
||||||
|
}
|
||||||
|
for(uint32_t i=0; i<ret->cmd_var_assigns.size(); i++)
|
||||||
|
{
|
||||||
|
ret->cmd_var_assigns[i].first = dynamic_cast<variable_t*>(obj_copy(t->cmd_var_assigns[i].first));
|
||||||
|
ret->cmd_var_assigns[i].second = dynamic_cast<arg_t*>(obj_copy(t->cmd_var_assigns[i].second));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_case :
|
||||||
|
{
|
||||||
|
case_t* t = dynamic_cast<case_t*>(o);
|
||||||
|
case_t* ret = new case_t(*t);
|
||||||
|
|
||||||
|
// carg
|
||||||
|
ret->carg = dynamic_cast<arg_t*>(obj_copy(t->carg));
|
||||||
|
// cases
|
||||||
|
for(uint32_t i=0; i<ret->cases.size(); i++)
|
||||||
|
{
|
||||||
|
for(uint32_t j=0; j<ret->cases[i].first.size(); i++)
|
||||||
|
ret->cases[i].first[j] = dynamic_cast<arg_t*>(obj_copy(t->cases[i].first[j]));
|
||||||
|
ret->cases[i].second = dynamic_cast<list_t*>(obj_copy(t->cases[i].second));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_if :
|
||||||
|
{
|
||||||
|
if_t* t = dynamic_cast<if_t*>(o);
|
||||||
|
if_t* ret = new if_t(*t);
|
||||||
|
|
||||||
|
// ifs
|
||||||
|
for(uint32_t i=0; i<ret->blocks.size(); i++)
|
||||||
|
{
|
||||||
|
// condition
|
||||||
|
ret->blocks[i].first = dynamic_cast<list_t*>(obj_copy(t->blocks[i].first));
|
||||||
|
// execution
|
||||||
|
ret->blocks[i].second = dynamic_cast<list_t*>(obj_copy(t->blocks[i].second));
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
ret->else_lst = dynamic_cast<list_t*>(obj_copy(t->else_lst));
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_for :
|
||||||
|
{
|
||||||
|
for_t* t = dynamic_cast<for_t*>(o);
|
||||||
|
for_t* ret = new for_t(*t);
|
||||||
|
|
||||||
|
// variable
|
||||||
|
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
|
||||||
|
// iterations
|
||||||
|
ret->iter = dynamic_cast<arglist_t*>(obj_copy(t->iter));
|
||||||
|
// for block
|
||||||
|
ret->ops = dynamic_cast<list_t*>(obj_copy(t->ops));
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::block_while :
|
||||||
|
{
|
||||||
|
while_t* t = dynamic_cast<while_t*>(o);
|
||||||
|
while_t* ret = new while_t(*t);
|
||||||
|
|
||||||
|
// condition
|
||||||
|
ret->cond = dynamic_cast<list_t*>(obj_copy(t->cond));
|
||||||
|
// for operations
|
||||||
|
ret->ops = dynamic_cast<list_t*>(obj_copy(t->ops));
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<ret->redirs.size(); i++)
|
||||||
|
ret->redirs[i] = dynamic_cast<redirect_t*>(obj_copy(t->redirs[i]));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::subarg_string :
|
||||||
|
{
|
||||||
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(o);
|
||||||
|
subarg_string_t* ret = new subarg_string_t(*t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::subarg_variable :
|
||||||
|
{
|
||||||
|
subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
|
||||||
|
subarg_variable_t* ret = new subarg_variable_t(*t);
|
||||||
|
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::subarg_subshell :
|
||||||
|
{
|
||||||
|
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
|
||||||
|
subarg_subshell_t* ret = new subarg_subshell_t(*t);
|
||||||
|
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::subarg_procsub :
|
||||||
|
{
|
||||||
|
subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
|
||||||
|
subarg_procsub_t* ret = new subarg_procsub_t(*t);
|
||||||
|
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::subarg_arithmetic :
|
||||||
|
{
|
||||||
|
subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
|
||||||
|
subarg_arithmetic_t* ret = new subarg_arithmetic_t(*t);
|
||||||
|
ret->arith = dynamic_cast<arithmetic_t*>(obj_copy(t->arith));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arithmetic_number :
|
||||||
|
{
|
||||||
|
arithmetic_number_t* t = dynamic_cast<arithmetic_number_t*>(o);
|
||||||
|
arithmetic_number_t* ret = new arithmetic_number_t(*t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arithmetic_variable :
|
||||||
|
{
|
||||||
|
arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
|
||||||
|
arithmetic_variable_t* ret = new arithmetic_variable_t(*t);
|
||||||
|
ret->var = dynamic_cast<variable_t*>(obj_copy(t->var));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arithmetic_subshell :
|
||||||
|
{
|
||||||
|
arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
|
||||||
|
arithmetic_subshell_t* ret = new arithmetic_subshell_t(*t);
|
||||||
|
ret->sbsh = dynamic_cast<subshell_t*>(obj_copy(t->sbsh));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arithmetic_operation :
|
||||||
|
{
|
||||||
|
arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
|
||||||
|
arithmetic_operation_t* ret = new arithmetic_operation_t(*t);
|
||||||
|
ret->val1 = dynamic_cast<arithmetic_t*>(obj_copy(t->val1));
|
||||||
|
ret->val2 = dynamic_cast<arithmetic_t*>(obj_copy(t->val2));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case _obj::arithmetic_parenthesis :
|
||||||
|
{
|
||||||
|
arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
|
||||||
|
arithmetic_parenthesis_t* ret = new arithmetic_parenthesis_t(*t);
|
||||||
|
ret->val = dynamic_cast<arithmetic_t*>(obj_copy(t->val));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: return nullptr; //dummy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //RECURSIVE_HPP
|
#endif //RECURSIVE_HPP
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
#define RESOLVE_HPP
|
#define RESOLVE_HPP
|
||||||
|
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
#include "parse.hpp"
|
||||||
|
|
||||||
extern std::vector<std::string> included;
|
extern std::vector<std::string> included;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, std::string const& filename, std::string* ex_dir=nullptr);
|
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir=nullptr);
|
||||||
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string const& filename, std::string* ex_dir=nullptr);
|
std::pair<std::string, std::string> do_resolve_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir=nullptr);
|
||||||
|
|
||||||
bool add_include(std::string const& file);
|
bool add_include(std::string const& file);
|
||||||
|
|
||||||
void resolve(_obj* sh, std::string* filename);
|
void resolve(_obj* sh, parse_context ctx);
|
||||||
void resolve(shmain* sh);
|
|
||||||
|
|
||||||
std::string _pre_cd(std::string const& filename);
|
std::string _pre_cd(std::string const& filename);
|
||||||
void _cd(std::string const& dir);
|
void _cd(std::string const& dir);
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ struct lxsh_fct {
|
||||||
std::vector<std::string> depends_on=std::vector<std::string>();
|
std::vector<std::string> depends_on=std::vector<std::string>();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const std::map<const std::string, const struct lxsh_fct> lxsh_extend_fcts;
|
extern const std::map<const std::string, const lxsh_fct> lxsh_extend_fcts;
|
||||||
extern const std::map<const std::string, const struct lxsh_fct> lxsh_array_fcts;
|
extern const std::map<const std::string, const lxsh_fct> lxsh_array_fcts;
|
||||||
extern const std::map<const std::string, const struct lxsh_fct> lxsh_allfcts;
|
extern const std::map<const std::string, const lxsh_fct> lxsh_allfcts;
|
||||||
|
|
||||||
void add_lxsh_fcts(shmain* sh, std::set<std::string> fcts);
|
void add_lxsh_fcts(shmain* sh, std::set<std::string> fcts);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,20 +62,67 @@ subarg: can be one of
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// pre-definitions
|
||||||
|
|
||||||
#define AND_OP false
|
#define AND_OP false
|
||||||
#define OR_OP true
|
#define OR_OP true
|
||||||
|
|
||||||
class condlist;
|
class condlist_t;
|
||||||
class block;
|
class block_t;
|
||||||
class pipeline;
|
class pipeline_t;
|
||||||
class arg;
|
class arg_t;
|
||||||
class subarg;
|
class subarg_t;
|
||||||
class cmd;
|
class cmd_t;
|
||||||
|
class redirect_t;
|
||||||
|
|
||||||
// type pack of condlist
|
// structs
|
||||||
typedef std::vector<arg*> arglist_t;
|
|
||||||
|
|
||||||
extern std::string g_origin;
|
struct parse_context {
|
||||||
|
const char* data=NULL;
|
||||||
|
uint64_t size=0;
|
||||||
|
uint64_t i=0;
|
||||||
|
const char* filename="";
|
||||||
|
bool bash=false;
|
||||||
|
const char* expecting="";
|
||||||
|
const char* here_delimiter="";
|
||||||
|
const char* here_doc="";
|
||||||
|
const char operator[](uint64_t a) { return data[a]; }
|
||||||
|
bool has_errored=false;
|
||||||
|
redirect_t* here_document=nullptr;
|
||||||
|
char* here_delimitor=NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct generate_context {
|
||||||
|
arg_t* here_document=nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// exceptions
|
||||||
|
|
||||||
|
class format_error : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Conctructor
|
||||||
|
inline format_error(const std::string& what, const std::string& origin, const std::string& data, int where, std::string level="error") { desc=what; index=where; filename=origin; sdat=data; severity=level; }
|
||||||
|
inline format_error(const std::string& what, parse_context const& ctx, std::string level="error") { desc=what; index=ctx.i; filename=ctx.filename; sdat=ctx.data; severity=level; }
|
||||||
|
//! @brief Error message
|
||||||
|
inline const char * what () const throw () {return desc.c_str();}
|
||||||
|
//! @brief Origin of the data, name of imported file, otherwise empty if generated
|
||||||
|
inline const char * origin() const throw () {return filename.c_str();}
|
||||||
|
//! @brief Data causing the exception
|
||||||
|
inline const char * data() const throw () {return sdat.c_str();}
|
||||||
|
//! @brief Severity of the exception
|
||||||
|
inline const std::string level() const throw () {return severity.c_str();}
|
||||||
|
//! @brief Where the error is located in the data
|
||||||
|
inline const int where () const throw () {return index;}
|
||||||
|
private:
|
||||||
|
std::string desc;
|
||||||
|
int index;
|
||||||
|
std::string filename;
|
||||||
|
std::string sdat;
|
||||||
|
std::string severity;
|
||||||
|
};
|
||||||
|
|
||||||
|
// objects
|
||||||
|
|
||||||
// meta object type
|
// meta object type
|
||||||
class _obj
|
class _obj
|
||||||
|
|
@ -83,13 +130,13 @@ 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;
|
||||||
|
|
@ -99,185 +146,204 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// meta arithmetic type
|
// meta arithmetic type
|
||||||
class arithmetic : public _obj
|
class arithmetic_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual std::string generate(int ind)=0;
|
virtual std::string generate(int ind)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// meta subarg type
|
// meta subarg type
|
||||||
class subarg : public _obj
|
class subarg_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~subarg() {;}
|
virtual ~subarg_t() {;}
|
||||||
virtual std::string generate(int ind)=0;
|
virtual std::string generate(int ind)=0;
|
||||||
|
|
||||||
bool quoted;
|
bool quoted;
|
||||||
};
|
};
|
||||||
|
|
||||||
class arg : public _obj
|
class arg_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
arg() { type=_obj::_arg; }
|
arg_t() { type=_obj::arg; forcequoted=false; }
|
||||||
arg(std::string const& str) { type=_obj::_arg; this->set(str);}
|
arg_t(std::string const& str, bool fquote=false) { type=_obj::arg; this->set(str); forcequoted=fquote; }
|
||||||
arg(subarg* in) { type=_obj::_arg; sa.push_back(in); }
|
arg_t(subarg_t* in, bool fquote=false) { type=_obj::arg; sa.push_back(in); forcequoted=fquote; }
|
||||||
~arg() { for(auto it: sa) delete it; }
|
~arg_t() { for(auto it: sa) delete it; }
|
||||||
|
|
||||||
void set(std::string const& str);
|
void set(std::string const& str);
|
||||||
|
|
||||||
void insert(uint32_t i, subarg* val);
|
void insert(uint32_t i, subarg_t* val);
|
||||||
void insert(uint32_t i, arg const& a);
|
void insert(uint32_t i, arg_t const& a);
|
||||||
void insert(uint32_t i, std::string const& in);
|
void insert(uint32_t i, std::string const& in);
|
||||||
|
|
||||||
inline void add(subarg* in) { sa.push_back(in); }
|
inline void add(subarg_t* in) { sa.push_back(in); }
|
||||||
void add(std::string const& in);
|
void add(std::string const& in);
|
||||||
inline size_t size() { return sa.size(); }
|
inline size_t size() { return sa.size(); }
|
||||||
|
|
||||||
std::vector<subarg*> sa;
|
std::vector<subarg_t*> sa;
|
||||||
|
|
||||||
|
// is forcequoted: var assign
|
||||||
|
bool forcequoted;
|
||||||
|
|
||||||
|
bool is_string();
|
||||||
// return if is a string and only one subarg
|
// return if is a string and only one subarg
|
||||||
std::string string();
|
std::string string();
|
||||||
// return if the first subarg is a string
|
// return if the first subarg is a string
|
||||||
std::string first_sa_string();
|
std::string first_sa_string();
|
||||||
|
|
||||||
|
// can expand into multiple arguments
|
||||||
|
bool can_expand();
|
||||||
|
|
||||||
inline bool equals(std::string const& in) { return this->string() == in; }
|
inline bool equals(std::string const& in) { return this->string() == in; }
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class variable : public _obj
|
class variable_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
variable(std::string const& in="", arg* i=nullptr, bool def=false, bool ismanip=false, arg* m=nullptr) { type=_obj::_variable; varname=in; index=i; definition=def; is_manip=ismanip; precedence=false; manip=m; }
|
variable_t(std::string const& in="", arg_t* i=nullptr, bool def=false, bool ismanip=false, arg_t* m=nullptr) { type=_obj::variable; varname=in; index=i; definition=def; is_manip=ismanip; precedence=false; manip=m; }
|
||||||
~variable() {
|
~variable_t() {
|
||||||
if(index!=nullptr) delete index;
|
if(index!=nullptr) delete index;
|
||||||
if(manip!=nullptr) delete manip;
|
if(manip!=nullptr) delete manip;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string varname;
|
std::string varname;
|
||||||
bool definition;
|
bool definition;
|
||||||
arg* index; // for bash specific
|
arg_t* index; // for bash specific
|
||||||
|
|
||||||
bool is_manip;
|
bool is_manip;
|
||||||
bool precedence;
|
bool precedence;
|
||||||
arg* manip;
|
arg_t* manip;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
// arglist
|
// arglist
|
||||||
|
|
||||||
class arglist : public _obj
|
class arglist_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
arglist() { type=_obj::_arglist; }
|
arglist_t() { type=_obj::arglist; }
|
||||||
arglist(arg* in) { type=_obj::_arglist; this->add(in); }
|
arglist_t(arg_t* in) { type=_obj::arglist; this->add(in); }
|
||||||
~arglist() { for( auto it: args ) delete it; }
|
~arglist_t() { for( auto it: args ) delete it; }
|
||||||
inline void add(arg* in) { args.push_back(in); }
|
inline void add(arg_t* in) { args.push_back(in); }
|
||||||
|
|
||||||
std::vector<arg*> args;
|
std::vector<arg_t*> args;
|
||||||
|
|
||||||
std::vector<std::string> strargs(uint32_t start);
|
std::vector<std::string> strargs(uint32_t start);
|
||||||
|
|
||||||
void insert(uint32_t i, arg* val);
|
// get first argument as string
|
||||||
void insert(uint32_t i, arglist const& lst);
|
std::string first_arg_string();
|
||||||
|
// potentially expands into more arguments than its size
|
||||||
|
bool can_expand();
|
||||||
|
|
||||||
|
void insert(uint32_t i, arg_t* val);
|
||||||
|
void insert(uint32_t i, arglist_t const& lst);
|
||||||
|
|
||||||
inline size_t size() { return args.size(); }
|
inline size_t size() { return args.size(); }
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class redirect : public _obj
|
class redirect_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; }
|
redirect_t(std::string strop="") { type=_obj::redirect; op=strop; target=nullptr; here_document=nullptr; }
|
||||||
redirect(arg* in) { type=_obj::_redirect; target=in; }
|
redirect_t(arg_t* in) { type=_obj::redirect; target=in; here_document=nullptr; }
|
||||||
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; }
|
redirect_t(std::string strop, arg_t* in) { type=_obj::redirect; op=strop; target=in; here_document=nullptr; }
|
||||||
~redirect() { if(target != nullptr) delete target; }
|
redirect_t(std::string strop, arg_t* in, arg_t* doc) { type=_obj::redirect; op=strop; target=in; here_document=doc; }
|
||||||
|
~redirect_t() {
|
||||||
|
if(target != nullptr) delete target;
|
||||||
|
if(here_document != nullptr) delete here_document;
|
||||||
|
}
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
|
|
||||||
std::string op;
|
std::string op;
|
||||||
arg* target;
|
arg_t* target;
|
||||||
|
arg_t* here_document;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Meta block
|
// Meta block
|
||||||
class block : public _obj
|
class block_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
block() { ; }
|
block_t() { ; }
|
||||||
virtual ~block() { for(auto it: redirs) delete it; }
|
virtual ~block_t() { for(auto it: redirs) delete it; }
|
||||||
// cmd
|
// cmd
|
||||||
std::vector<redirect*> redirs;
|
std::vector<redirect_t*> redirs;
|
||||||
|
|
||||||
// subshell: return the containing cmd, if it is a single command
|
// subshell: return the containing cmd, if it is a single command
|
||||||
cmd* single_cmd();
|
cmd_t* single_cmd();
|
||||||
|
|
||||||
std::string generate_redirs(int ind, std::string const& _str);
|
std::string generate_redirs(int ind, std::string const& _str, generate_context* ctx);
|
||||||
|
|
||||||
virtual std::string generate(int ind)=0;
|
virtual std::string generate(int ind, generate_context* ctx)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// PL
|
// PL
|
||||||
|
|
||||||
class pipeline : public _obj
|
class pipeline_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
pipeline(block* bl=nullptr) { type=_obj::_pipeline; if(bl!=nullptr) cmds.push_back(bl); negated=false; }
|
pipeline_t(block_t* bl=nullptr) { type=_obj::pipeline; if(bl!=nullptr) cmds.push_back(bl); negated=false; bash_time=false; }
|
||||||
~pipeline() { for(auto it: cmds) delete it; }
|
~pipeline_t() { for(auto it: cmds) delete it; }
|
||||||
inline void add(block* bl) { this->cmds.push_back(bl); }
|
inline void add(block_t* bl) { this->cmds.push_back(bl); }
|
||||||
std::vector<block*> cmds;
|
std::vector<block_t*> cmds;
|
||||||
|
|
||||||
bool negated; // negated return value (! at start)
|
bool negated; // negated return value (! at start)
|
||||||
|
bool bash_time; // has bash time command
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); };
|
||||||
};
|
};
|
||||||
|
|
||||||
// CL
|
// CL
|
||||||
|
|
||||||
class condlist : public _obj
|
class condlist_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
condlist() { type=_obj::_condlist; parallel=false; }
|
condlist_t() { type=_obj::condlist; parallel=false; }
|
||||||
condlist(pipeline* pl) { type=_obj::_condlist; parallel=false; this->add(pl); }
|
condlist_t(pipeline_t* pl) { type=_obj::condlist; parallel=false; this->add(pl); }
|
||||||
condlist(block* bl);
|
condlist_t(block_t* bl);
|
||||||
~condlist() { for(auto it: pls) delete it; }
|
~condlist_t() { for(auto it: pls) delete it; }
|
||||||
|
|
||||||
bool parallel; // & at the end
|
bool parallel; // & at the end
|
||||||
|
|
||||||
void add(pipeline* pl, bool or_op=false);
|
void add(pipeline_t* pl, bool or_op=false);
|
||||||
|
|
||||||
// don't push_back here, use add() instead
|
// don't push_back here, use add() instead
|
||||||
std::vector<pipeline*> pls;
|
std::vector<pipeline_t*> pls;
|
||||||
std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines
|
std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines
|
||||||
|
|
||||||
void prune_first_cmd();
|
void prune_first_cmd();
|
||||||
|
|
||||||
block* first_block();
|
block_t* first_block();
|
||||||
cmd* first_cmd();
|
cmd_t* first_cmd();
|
||||||
cmd* get_cmd(std::string const& cmdname);
|
cmd_t* get_cmd(std::string const& cmdname);
|
||||||
|
|
||||||
void negate();
|
void negate();
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class list : public _obj
|
class list_t : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
list() { type=_obj::_list; }
|
list_t() { type=_obj::list; }
|
||||||
list(condlist* in) { type=_obj::_list; this->add(in); }
|
list_t(condlist_t* in) { type=_obj::list; this->add(in); }
|
||||||
~list() { for(auto it: cls) delete it; }
|
~list_t() { for(auto it: cls) delete it; }
|
||||||
|
|
||||||
void clear() { for(auto it: cls) delete it; cls.resize(0); }
|
void clear() { for(auto it: cls) delete it; cls.resize(0); }
|
||||||
|
|
||||||
std::vector<condlist*> cls;
|
std::vector<condlist_t*> cls;
|
||||||
inline void add(condlist* in) { cls.push_back(in); }
|
inline void add(condlist_t* in) { cls.push_back(in); }
|
||||||
|
|
||||||
condlist* last_cond() { return cls[cls.size()-1]; }
|
condlist_t* last_cond() { return cls[cls.size()-1]; }
|
||||||
|
|
||||||
void insert(uint32_t i, condlist* val);
|
void insert(uint32_t i, condlist_t* val);
|
||||||
void insert(uint32_t i, list const& lst);
|
void insert(uint32_t i, list_t const& lst);
|
||||||
|
|
||||||
size_t size() { return cls.size(); }
|
size_t size() { return cls.size(); }
|
||||||
|
|
||||||
|
|
@ -285,27 +351,22 @@ public:
|
||||||
std::string generate(int ind) { return this->generate(ind, true); }
|
std::string generate(int ind) { return this->generate(ind, true); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// class redir
|
|
||||||
// {
|
|
||||||
// public:
|
|
||||||
// enum redirtype { none, write, append, read, raw } ;
|
|
||||||
// redir(redirtype in=none) { type=in; }
|
|
||||||
// redirtype type;
|
|
||||||
// arg val;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// block subtypes //
|
// block subtypes //
|
||||||
|
|
||||||
class cmd : public block
|
class cmd_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cmd(arglist* in=nullptr) { type=_obj::block_cmd; args=in; is_cmdvar=false; }
|
cmd_t(arglist_t* in=nullptr) { type=_obj::block_cmd; args=in; is_cmdvar=false; }
|
||||||
~cmd() {
|
~cmd_t() {
|
||||||
if(args!=nullptr) delete args;
|
if(args!=nullptr) delete args;
|
||||||
for(auto it: var_assigns) {
|
for(auto it: var_assigns) {
|
||||||
delete it.first;
|
delete it.first;
|
||||||
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;
|
||||||
|
|
@ -314,30 +375,36 @@ public:
|
||||||
|
|
||||||
size_t arglist_size();
|
size_t arglist_size();
|
||||||
|
|
||||||
void add(arg* in);
|
void add(arg_t* in);
|
||||||
|
|
||||||
|
|
||||||
// preceding var assigns
|
// preceding var assigns
|
||||||
std::vector<std::pair<variable*,arg*>> var_assigns;
|
std::vector<std::pair<variable_t*,arg_t*>> var_assigns;
|
||||||
|
|
||||||
// is a cmdvar type
|
// is a cmdvar type
|
||||||
bool is_cmdvar;
|
bool is_cmdvar;
|
||||||
|
// var assigns on cmdvar
|
||||||
|
std::vector<std::pair<variable_t*,arg_t*>> cmd_var_assigns;
|
||||||
|
|
||||||
// check if cmd is this (ex: unset)
|
// check if cmd is this (ex: unset)
|
||||||
bool is(std::string const& in);
|
bool is(std::string const& in);
|
||||||
// for var assigns in special cmds (export, unset, read, local)
|
// for var assigns in special cmds (export, unset, read, local)
|
||||||
bool is_argvar();
|
bool is_argvar();
|
||||||
std::vector<subarg*> subarg_vars();
|
std::vector<subarg_t*> subarg_vars();
|
||||||
|
|
||||||
arglist* args;
|
// returns true if command performs env var changes
|
||||||
|
bool has_var_assign();
|
||||||
|
|
||||||
std::string generate(int ind);
|
arglist_t* args;
|
||||||
|
|
||||||
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class shmain : public block
|
class shmain : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
shmain(list* in=nullptr) { type=_obj::block_main; lst=in; }
|
shmain(list_t* in=nullptr) { type=_obj::block_main; if(in == nullptr) lst = new list_t; else lst=in; }
|
||||||
~shmain() {
|
~shmain() {
|
||||||
if(lst!=nullptr) delete lst;
|
if(lst!=nullptr) delete lst;
|
||||||
}
|
}
|
||||||
|
|
@ -346,62 +413,66 @@ public:
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string shebang;
|
std::string shebang;
|
||||||
list* lst;
|
list_t* lst;
|
||||||
|
|
||||||
std::string generate(bool print_shebang=true, int ind=0);
|
std::string generate(bool print_shebang=true, int ind=0);
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class subshell : public block
|
class subshell_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
subshell(list* in=nullptr) { type=_obj::block_subshell; lst=in; }
|
subshell_t(list_t* in=nullptr) { type=_obj::block_subshell; lst=in; }
|
||||||
subshell(block* in) { type=_obj::block_subshell; lst=new list(new condlist(in)); }
|
subshell_t(block_t* in) { type=_obj::block_subshell; lst=new list_t(new condlist_t(in)); }
|
||||||
~subshell() {
|
~subshell_t() {
|
||||||
if(lst!=nullptr) delete lst;
|
if(lst!=nullptr) delete lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* single_cmd();
|
cmd_t* single_cmd();
|
||||||
|
|
||||||
list* lst;
|
list_t* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class brace : public block
|
class brace_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
brace(list* in=nullptr) { type=_obj::block_brace; lst=in; }
|
brace_t(list_t* in=nullptr) { type=_obj::block_brace; lst=in; }
|
||||||
~brace() {
|
~brace_t() {
|
||||||
if(lst!=nullptr) delete lst;
|
if(lst!=nullptr) delete lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* single_cmd();
|
cmd_t* single_cmd();
|
||||||
|
|
||||||
list* lst;
|
list_t* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class function : public block
|
class function_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
function(list* in=nullptr) { type=_obj::block_function; lst=in; }
|
function_t(list_t* in=nullptr) { type=_obj::block_function; lst=in; }
|
||||||
~function() {
|
~function_t() {
|
||||||
if(lst!=nullptr) delete lst;
|
if(lst!=nullptr) delete lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
list* lst;
|
list_t* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class case_block : public block
|
class case_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
case_block(arg* in=nullptr) { type=_obj::block_case; carg=in; }
|
case_t(arg_t* in=nullptr) { type=_obj::block_case; carg=in; }
|
||||||
~case_block() {
|
~case_t() {
|
||||||
if(carg!=nullptr) delete carg;
|
if(carg!=nullptr) delete carg;
|
||||||
for( auto cit : cases )
|
for( auto cit : cases )
|
||||||
{
|
{
|
||||||
|
|
@ -411,17 +482,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arg* carg;
|
arg_t* carg;
|
||||||
std::vector< std::pair<std::vector<arg*>, list*> > cases;
|
std::vector< std::pair<std::vector<arg_t*>, list_t*> > cases;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class if_block : public block
|
class if_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
if_block() { type=_obj::block_if; else_lst=nullptr; }
|
if_t() { type=_obj::block_if; else_lst=nullptr; }
|
||||||
~if_block() {
|
~if_t() {
|
||||||
for(auto ifb: blocks)
|
for(auto ifb: blocks)
|
||||||
{
|
{
|
||||||
if(ifb.first!=nullptr) delete ifb.first;
|
if(ifb.first!=nullptr) delete ifb.first;
|
||||||
|
|
@ -430,173 +502,179 @@ public:
|
||||||
if(else_lst!=nullptr) delete else_lst;
|
if(else_lst!=nullptr) delete else_lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector< std::pair<list*,list*> > blocks;
|
std::vector< std::pair<list_t*,list_t*> > blocks;
|
||||||
|
|
||||||
list* else_lst;
|
list_t* else_lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class for_block : public block
|
class for_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
for_block(variable* in=nullptr, arglist* args=nullptr, list* lst=nullptr) { type=_obj::block_for; var=in; iter=args; ops=lst; }
|
for_t(variable_t* in=nullptr, arglist_t* args=nullptr, list_t* lst=nullptr, bool ii=false) { type=_obj::block_for; var=in; iter=args; ops=lst; in_val=ii; }
|
||||||
~for_block() {
|
~for_t() {
|
||||||
if(iter!=nullptr) delete iter;
|
if(iter!=nullptr) delete iter;
|
||||||
if(ops!=nullptr) delete ops;
|
if(ops!=nullptr) delete ops;
|
||||||
if(var!=nullptr) delete var;
|
if(var!=nullptr) delete var;
|
||||||
}
|
}
|
||||||
|
|
||||||
variable* var;
|
variable_t* var;
|
||||||
|
|
||||||
arglist* iter;
|
arglist_t* iter;
|
||||||
list* ops;
|
list_t* ops;
|
||||||
|
|
||||||
std::string generate(int ind);
|
bool in_val;
|
||||||
|
|
||||||
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class while_block : public block
|
class while_t : public block_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
while_block(list* a=nullptr, list* b=nullptr) { type=_obj::block_while; cond=a; ops=b; }
|
while_t(list_t* a=nullptr, list_t* b=nullptr) { type=_obj::block_while; cond=a; ops=b; }
|
||||||
~while_block() {
|
~while_t() {
|
||||||
if(cond!=nullptr) delete cond;
|
if(cond!=nullptr) delete cond;
|
||||||
if(ops!=nullptr) delete ops;
|
if(ops!=nullptr) delete ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
condlist* real_condition() { return cond->last_cond(); }
|
condlist_t* real_condition() { return cond->last_cond(); }
|
||||||
|
|
||||||
list* cond;
|
list_t* cond;
|
||||||
list* ops;
|
list_t* ops;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subarg subtypes //
|
// Subarg subtypes //
|
||||||
|
|
||||||
class string_subarg : public subarg
|
class subarg_string_t : public subarg_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
string_subarg(std::string const& in="") { type=_obj::subarg_string; val=in; }
|
subarg_string_t(std::string const& in="") { type=_obj::subarg_string; val=in; }
|
||||||
~string_subarg() {;}
|
~subarg_string_t() {;}
|
||||||
|
|
||||||
std::string val;
|
std::string val;
|
||||||
|
|
||||||
std::string generate(int ind) { return val; }
|
std::string generate(int ind) { return val; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class variable_subarg : public subarg
|
class subarg_variable_t : public subarg_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
variable_subarg(variable* in=nullptr, bool inq=false) { type=_obj::subarg_variable; var=in; quoted=inq; }
|
subarg_variable_t(variable_t* in=nullptr, bool inq=false) { type=_obj::subarg_variable; var=in; quoted=inq; }
|
||||||
~variable_subarg() {
|
~subarg_variable_t() {
|
||||||
if(var!=nullptr) delete var;
|
if(var!=nullptr) delete var;
|
||||||
}
|
}
|
||||||
|
|
||||||
variable* var;
|
variable_t* var;
|
||||||
|
|
||||||
std::string generate(int ind) { return "$" + var->generate(ind); }
|
std::string generate(int ind) { return "$" + var->generate(ind); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class arithmetic_subarg : public subarg
|
class subarg_arithmetic_t : public subarg_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
arithmetic_subarg(arithmetic* a=nullptr) { type=_obj::subarg_arithmetic; arith=a; }
|
subarg_arithmetic_t(arithmetic_t* a=nullptr) { type=_obj::subarg_arithmetic; arith=a; }
|
||||||
~arithmetic_subarg() {
|
~subarg_arithmetic_t() {
|
||||||
if(arith!=nullptr) delete arith;
|
if(arith!=nullptr) delete arith;
|
||||||
}
|
}
|
||||||
|
|
||||||
arithmetic* arith;
|
arithmetic_t* arith;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class subshell_subarg : public subarg
|
class subarg_subshell_t : public subarg_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
subshell_subarg(subshell* in=nullptr, bool inq=false) { type=_obj::subarg_subshell; sbsh=in; quoted=inq; }
|
subarg_subshell_t(subshell_t* in=nullptr, bool inq=false, bool is_backtick=false) { type=_obj::subarg_subshell; sbsh=in; quoted=inq; backtick=is_backtick; }
|
||||||
~subshell_subarg() { if(sbsh != nullptr) delete sbsh; }
|
~subarg_subshell_t() { if(sbsh != nullptr) delete sbsh; }
|
||||||
|
|
||||||
subshell* sbsh;
|
subshell_t* sbsh;
|
||||||
|
bool backtick;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class procsub_subarg : public subarg
|
class subarg_procsub_t : public subarg_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
procsub_subarg() { type=_obj::subarg_procsub; sbsh=nullptr; is_output=false; }
|
subarg_procsub_t() { type=_obj::subarg_procsub; sbsh=nullptr; is_output=false; }
|
||||||
procsub_subarg(bool output, subshell* in) { type=_obj::subarg_procsub; sbsh=in; is_output=output; }
|
subarg_procsub_t(bool output, subshell_t* in) { type=_obj::subarg_procsub; sbsh=in; is_output=output; }
|
||||||
~procsub_subarg() { if(sbsh!=nullptr) delete sbsh; }
|
~subarg_procsub_t() { if(sbsh!=nullptr) delete sbsh; }
|
||||||
|
|
||||||
bool is_output;
|
bool is_output;
|
||||||
subshell* sbsh;
|
subshell_t* sbsh;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Arithmetic subtypes //
|
// Arithmetic subtypes //
|
||||||
|
|
||||||
class operation_arithmetic : public arithmetic
|
class arithmetic_operation_t : public arithmetic_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
operation_arithmetic(std::string op="", arithmetic* a=nullptr, arithmetic* b=nullptr, bool pre=false) { type=_obj::arithmetic_operation; oper=op; val1=a; val2=b; precedence=pre; }
|
arithmetic_operation_t(std::string op="", arithmetic_t* a=nullptr, arithmetic_t* b=nullptr, bool pre=false) { type=_obj::arithmetic_operation; oper=op; val1=a; val2=b; precedence=pre; }
|
||||||
~operation_arithmetic() {
|
~arithmetic_operation_t() {
|
||||||
if(val1 != nullptr) delete val1;
|
if(val1 != nullptr) delete val1;
|
||||||
if(val2 != nullptr) delete val2;
|
if(val2 != nullptr) delete val2;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string oper;
|
std::string oper;
|
||||||
bool precedence;
|
bool precedence;
|
||||||
arithmetic *val1, *val2;
|
arithmetic_t *val1, *val2;
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class subshell_arithmetic : public arithmetic
|
class arithmetic_subshell_t : public arithmetic_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
subshell_arithmetic(subshell* a=nullptr) { type=_obj::arithmetic_subshell; sbsh=a; }
|
arithmetic_subshell_t(subshell_t* a=nullptr) { type=_obj::arithmetic_subshell; sbsh=a; }
|
||||||
~subshell_arithmetic() {
|
~arithmetic_subshell_t() {
|
||||||
if(sbsh!=nullptr) delete sbsh;
|
if(sbsh!=nullptr) delete sbsh;
|
||||||
}
|
}
|
||||||
|
|
||||||
subshell* sbsh;
|
subshell_t* sbsh;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class parenthesis_arithmetic : public arithmetic
|
class arithmetic_parenthesis_t : public arithmetic_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
parenthesis_arithmetic(arithmetic* a=nullptr) { type=_obj::arithmetic_parenthesis; val=a; }
|
arithmetic_parenthesis_t(arithmetic_t* a=nullptr) { type=_obj::arithmetic_parenthesis; val=a; }
|
||||||
~parenthesis_arithmetic() {
|
~arithmetic_parenthesis_t() {
|
||||||
if(val!=nullptr) delete val;
|
if(val!=nullptr) delete val;
|
||||||
}
|
}
|
||||||
|
|
||||||
arithmetic* val;
|
arithmetic_t* val;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
||||||
class number_arithmetic : public arithmetic
|
class arithmetic_number_t : public arithmetic_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
number_arithmetic(std::string const& a) { type=_obj::arithmetic_number; val=a; }
|
arithmetic_number_t(std::string const& a) { type=_obj::arithmetic_number; val=a; }
|
||||||
|
|
||||||
std::string val;
|
std::string val;
|
||||||
|
|
||||||
std::string generate(int ind) { return val; }
|
std::string generate(int ind) { return val; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class variable_arithmetic : public arithmetic
|
class arithmetic_variable_t : public arithmetic_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
variable_arithmetic(variable* in=nullptr) { type=_obj::arithmetic_variable; var=in; }
|
arithmetic_variable_t(variable_t* in=nullptr) { type=_obj::arithmetic_variable; var=in; }
|
||||||
~variable_arithmetic() {
|
~arithmetic_variable_t() {
|
||||||
if(var!=nullptr) delete var;
|
if(var!=nullptr) delete var;
|
||||||
}
|
}
|
||||||
|
|
||||||
variable* var;
|
variable_t* var;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,34 +4,43 @@
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
|
||||||
// makers
|
// makers
|
||||||
arg* make_arg(std::string const& in);
|
arg_t* make_arg(std::string const& in);
|
||||||
|
|
||||||
cmd* make_cmd(std::vector<std::string> const& args);
|
cmd_t* make_cmd(std::vector<const char*> const& args);
|
||||||
cmd* make_cmd(std::vector<arg*> const& args);
|
cmd_t* make_cmd(std::vector<std::string> const& args);
|
||||||
cmd* make_cmd(std::string const& in);
|
cmd_t* make_cmd(std::vector<arg_t*> const& args);
|
||||||
|
cmd_t* make_cmd(std::string const& in);
|
||||||
|
|
||||||
pipeline* make_pipeline(std::vector<block*> const& bls);
|
pipeline_t* make_pipeline(std::vector<block_t*> const& bls);
|
||||||
pipeline* make_pipeline(std::string const& in);
|
pipeline_t* make_pipeline(std::string const& in);
|
||||||
|
|
||||||
condlist* make_condlist(std::string const& in);
|
condlist_t* make_condlist(std::string const& in);
|
||||||
list* make_list(std::string const& in);
|
list_t* make_list(std::string const& in);
|
||||||
|
|
||||||
block* make_block(std::string const& in);
|
block_t* make_block(std::string const& in);
|
||||||
|
|
||||||
// copy
|
// copy
|
||||||
arg* copy(arg* in);
|
arg_t* copy(arg_t* in);
|
||||||
variable* copy(variable* in);
|
variable_t* copy(variable_t* in);
|
||||||
|
|
||||||
// testers
|
// testers
|
||||||
bool arg_has_char(char c, arg* in);
|
bool arg_has_char(char c, arg_t* in);
|
||||||
bool possibly_expands(arg* in);
|
bool possibly_expands(arg_t* in);
|
||||||
bool possibly_expands(arglist* in);
|
bool possibly_expands(arglist_t* in);
|
||||||
|
|
||||||
// modifiers
|
// modifiers
|
||||||
void force_quotes(arg* in);
|
void force_quotes(arg_t* in);
|
||||||
void add_quotes(arg* in);
|
void add_quotes(arg_t* in);
|
||||||
|
|
||||||
|
cmd_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 a, std::string const& b) { return a.equals(b); }
|
inline bool operator==(arg_t a, std::string const& b) { return a.equals(b); }
|
||||||
|
|
||||||
#endif //STRUC_HELPER_HPP
|
#endif //STRUC_HELPER_HPP
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include <ztd/filedat.hpp>
|
|
||||||
|
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
|
||||||
extern std::string indenting_string;
|
extern std::string indenting_string;
|
||||||
|
|
@ -26,8 +24,6 @@ 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);
|
||||||
|
|
||||||
|
|
@ -130,6 +126,17 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -139,6 +146,12 @@ 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);
|
||||||
|
|
@ -148,10 +161,8 @@ 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(ztd::format_error const& e, bool print_line=true);
|
void printFormatError(format_error const& e, bool print_line=true);
|
||||||
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line=true);
|
|
||||||
|
|
||||||
int execute(shmain* sh, std::vector<std::string>& args);
|
|
||||||
|
|
||||||
#endif //UTIL_HPP
|
#endif //UTIL_HPP
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef VERSION_H
|
#ifndef VERSION_H
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
#define VERSION_STRING "v1.1.0"
|
#define VERSION_STRING "v1.5"
|
||||||
|
|
||||||
#endif //VERSION_H
|
#endif //VERSION_H
|
||||||
|
|
|
||||||
233
run-tests.sh
Executable file
233
run-tests.sh
Executable file
|
|
@ -0,0 +1,233 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
bin=${1-./lxsh}
|
||||||
|
|
||||||
|
echo_red()
|
||||||
|
{
|
||||||
|
printf "\033[1;31m%s\033[0m\n" "$*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
err=0
|
||||||
|
|
||||||
|
# $1 = file , $2 = extra print
|
||||||
|
# _LXSH_OPT : lxsh options
|
||||||
|
compile_test()
|
||||||
|
{
|
||||||
|
printf "%s%s: " "$1" "$2"
|
||||||
|
if errout=$($bin $_LXSH_OPT "$1" 2>&1 >/dev/null)
|
||||||
|
then
|
||||||
|
echo "Ok"
|
||||||
|
else
|
||||||
|
echo_red "Error"
|
||||||
|
echo "$errout"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 = runner , $2 = file , $3 = extra print , $4 = runtime for lxsh
|
||||||
|
# _LXSH_OPT : lxsh options
|
||||||
|
exec_test()
|
||||||
|
{
|
||||||
|
run=$1
|
||||||
|
lxshrun=${4-$run}
|
||||||
|
ret1=$($run "$2")
|
||||||
|
stat1=$?
|
||||||
|
ret2=$($bin $_LXSH_OPT "$2" | $lxshrun)
|
||||||
|
stat2=$?
|
||||||
|
printf "%s%s: " "$2" "$3"
|
||||||
|
if [ "$ret1" = "$ret2" ] && [ $stat1 -eq $stat2 ]
|
||||||
|
then echo "Ok"
|
||||||
|
else
|
||||||
|
echo_red "Error"
|
||||||
|
echo ">> original stat $stat1
|
||||||
|
$ret1
|
||||||
|
>> compiled stat $stat2
|
||||||
|
$ret2"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
size_test()
|
||||||
|
{
|
||||||
|
shebang=$(head -n1 "$1" | grep '^#!')
|
||||||
|
c1=$($bin --no-shebang -m "$1" | wc -c)
|
||||||
|
c2=$($bin -m "$1" | shfmt -mn | wc -c)
|
||||||
|
printf "%s%s: " "$1" "$2"
|
||||||
|
if [ $c1 -lt $c2 ]
|
||||||
|
then echo "Ok"
|
||||||
|
else
|
||||||
|
echo_red "Too big"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 = file , $2 = extra print , $3 = list , $@ = run options
|
||||||
|
list_test()
|
||||||
|
{
|
||||||
|
printf "%s%s: " "$1" "$2"
|
||||||
|
file=$1
|
||||||
|
varlist=$3
|
||||||
|
shift 3
|
||||||
|
diffout=$(diff <($bin "$file" "$@" | sort -k2) <(echo "$varlist" | sed '/^$/d' | sort -k2) )
|
||||||
|
if [ -z "$diffout" ] ; then
|
||||||
|
echo "Ok"
|
||||||
|
else
|
||||||
|
echo_red "Variable mismatch"
|
||||||
|
echo "$diffout"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve="test/include.sh test/resolve.sh"
|
||||||
|
exec_exclude="test/prompt.sh $resolve"
|
||||||
|
|
||||||
|
|
||||||
|
echo "
|
||||||
|
============
|
||||||
|
| sh |
|
||||||
|
============
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "== Parse =="
|
||||||
|
for I in test/*.sh
|
||||||
|
do
|
||||||
|
compile_test "$I" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Exec =="
|
||||||
|
for I in $( echo test/*.sh $exec_exclude | tr -s ' \n' '\n' | sort | uniq -u )
|
||||||
|
do
|
||||||
|
exec_test sh "$I" || err=$((err+1))
|
||||||
|
_LXSH_OPT=-M exec_test sh "$I" " (minify)" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Size =="
|
||||||
|
for I in test/*.sh
|
||||||
|
do
|
||||||
|
size_test "$I" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Resolve =="
|
||||||
|
|
||||||
|
for I in $resolve
|
||||||
|
do
|
||||||
|
printf "%s: " "$I"
|
||||||
|
if errmsg=$($bin "$I" | sh 2>&1 >/dev/null) && [ -z "$errmsg" ]
|
||||||
|
then echo "Ok"
|
||||||
|
else
|
||||||
|
echo_red "Error"
|
||||||
|
echo ">> stderr
|
||||||
|
$errmsg"
|
||||||
|
err=$((err+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
varlist="
|
||||||
|
2 nul
|
||||||
|
2 ABCD
|
||||||
|
1 AYE
|
||||||
|
1 BAR
|
||||||
|
3 FOO
|
||||||
|
2 TATA
|
||||||
|
1 TITI
|
||||||
|
4 TOTO
|
||||||
|
1 TUTU
|
||||||
|
4 somevar
|
||||||
|
"
|
||||||
|
|
||||||
|
vardefs="
|
||||||
|
1 ABCD
|
||||||
|
1 BAR
|
||||||
|
2 FOO
|
||||||
|
1 TATA
|
||||||
|
1 TOTO
|
||||||
|
1 TUTU
|
||||||
|
1 nul
|
||||||
|
2 somevar
|
||||||
|
"
|
||||||
|
|
||||||
|
varcalls="
|
||||||
|
1 AYE
|
||||||
|
1 ABCD
|
||||||
|
1 FOO
|
||||||
|
1 TATA
|
||||||
|
1 TITI
|
||||||
|
3 TOTO
|
||||||
|
1 nul
|
||||||
|
2 somevar
|
||||||
|
"
|
||||||
|
|
||||||
|
varlist_used="
|
||||||
|
1 AYE
|
||||||
|
2 ABCD
|
||||||
|
3 FOO
|
||||||
|
2 TATA
|
||||||
|
1 TITI
|
||||||
|
4 TOTO
|
||||||
|
2 nul
|
||||||
|
4 somevar
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "== Variables =="
|
||||||
|
{
|
||||||
|
list_test test/var.sh " (list)" "$varlist" --list-var || err=$((err+1))
|
||||||
|
list_test test/var.sh " (list-def)" "$vardefs" --list-var-def || err=$((err+1))
|
||||||
|
list_test test/var.sh " (list-call)" "$varcalls" --list-var-call || err=$((err+1))
|
||||||
|
list_test test/var.sh " (remove unused)" "$varlist_used" --remove-unused --list-var || err=$((err+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fctlist="
|
||||||
|
1 toto
|
||||||
|
1 tata
|
||||||
|
"
|
||||||
|
|
||||||
|
fctlist_used="
|
||||||
|
1 toto
|
||||||
|
"
|
||||||
|
|
||||||
|
cmdlist="
|
||||||
|
2 echo
|
||||||
|
1 toto
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "== Functions =="
|
||||||
|
{
|
||||||
|
list_test test/fct.sh " (list-fct)" "$fctlist" --list-fct || err=$((err+1))
|
||||||
|
list_test test/fct.sh " (list-cmd)" "$cmdlist" --list-cmd || err=$((err+1))
|
||||||
|
list_test test/fct.sh " (remove unused)" "$fctlist_used" --remove-unused --list-fct || err=$((err+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "
|
||||||
|
============
|
||||||
|
| bash |
|
||||||
|
============
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "== Parse =="
|
||||||
|
for I in test/*.bash
|
||||||
|
do
|
||||||
|
compile_test "$I" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Exec =="
|
||||||
|
for I in test/*.bash
|
||||||
|
do
|
||||||
|
exec_test bash "$I" || err=$((err+1))
|
||||||
|
_LXSH_OPT=-m exec_test bash "$I" " (minify)" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Size =="
|
||||||
|
for I in test/*.bash
|
||||||
|
do
|
||||||
|
size_test "$I" || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== Debashify =="
|
||||||
|
for I in test/{debashify.bash,array.bash,echo.bash}
|
||||||
|
do
|
||||||
|
_LXSH_OPT=--debashify exec_test bash "$I" "" sh || err=$((err+1))
|
||||||
|
_LXSH_OPT="-m --debashify" exec_test bash "$I" " (minify)" sh || err=$((err+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $err
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
_lxsh_array_create() {
|
_lxsh_array_create() {
|
||||||
printf "%s" "$1"
|
printf "%s" "$1"
|
||||||
shift 1
|
shift 1 2>/dev/null || return
|
||||||
for N ; do
|
for N ; do
|
||||||
printf "\t%s" "$N"
|
printf "\t%s" "$N"
|
||||||
done
|
done
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
157
src/exec.cpp
157
src/exec.cpp
|
|
@ -18,16 +18,16 @@
|
||||||
#define PIPE_READ 0
|
#define PIPE_READ 0
|
||||||
#define PIPE_WRITE 1
|
#define PIPE_WRITE 1
|
||||||
|
|
||||||
std::vector<condlist*> do_include_exec(condlist* cmd, std::string const& filename, FILE* fd)
|
std::vector<condlist_t*> do_include_exec(condlist_t* cmd, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist_t*> ret;
|
||||||
|
|
||||||
std::string dir;
|
std::string dir;
|
||||||
auto incs=do_include_raw(cmd, filename, &dir);
|
auto incs=do_include_raw(cmd, ctx, &dir);
|
||||||
|
|
||||||
for(auto it: incs)
|
for(auto it: incs)
|
||||||
{
|
{
|
||||||
parse_exec(fd, it.second, it.first);
|
parse_exec(fd, make_context(ctx, it.second, it.first));
|
||||||
}
|
}
|
||||||
// cd back
|
// cd back
|
||||||
_cd(dir);
|
_cd(dir);
|
||||||
|
|
@ -36,24 +36,24 @@ std::vector<condlist*> do_include_exec(condlist* cmd, std::string const& filenam
|
||||||
}
|
}
|
||||||
|
|
||||||
// if first is nullptr: is a string
|
// if first is nullptr: is a string
|
||||||
std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filename, FILE* fd)
|
std::vector<condlist_t*> do_resolve_exec(condlist_t* cmd, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist_t*> ret;
|
||||||
|
|
||||||
std::pair<std::string,std::string> p;
|
std::pair<std::string,std::string> p;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// get
|
// get
|
||||||
std::string dir;
|
std::string dir;
|
||||||
p=do_resolve_raw(cmd, filename, &dir);
|
p=do_resolve_raw(cmd, ctx, &dir);
|
||||||
// do parse
|
// do parse
|
||||||
parse_exec(fd, p.second, filename);
|
parse_exec(fd, make_context(ctx, p.second, p.first));
|
||||||
// cd back
|
// cd back
|
||||||
_cd(dir);
|
_cd(dir);
|
||||||
}
|
}
|
||||||
catch(ztd::format_error& e)
|
catch(format_error& e)
|
||||||
{
|
{
|
||||||
throw ztd::format_error(e.what(), '`'+p.first+'`', e.data(), e.where());
|
throw format_error(e.what(), '`'+p.first+'`', e.data(), e.where());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -61,9 +61,9 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filenam
|
||||||
|
|
||||||
// -- OBJECT CALLS --
|
// -- OBJECT CALLS --
|
||||||
|
|
||||||
bool resolve_condlist_exec(condlist* in, std::string const& filename, FILE* fd)
|
bool resolve_condlist_exec(condlist_t* in, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
cmd* tc = in->first_cmd();
|
cmd_t* tc = in->first_cmd();
|
||||||
if(tc == nullptr)
|
if(tc == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -71,23 +71,23 @@ bool resolve_condlist_exec(condlist* in, std::string const& filename, FILE* fd)
|
||||||
|
|
||||||
if(g_include && strcmd == "%include")
|
if(g_include && strcmd == "%include")
|
||||||
{
|
{
|
||||||
do_include_exec(in, filename, fd);
|
do_include_exec(in, ctx, fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(g_resolve && strcmd == "%resolve")
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
{
|
{
|
||||||
do_resolve_exec(in, filename, fd);
|
do_resolve_exec(in, ctx, fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool resolve_exec(condlist* in, std::string const& filename, FILE* fd)
|
bool resolve_exec(condlist_t* in, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
if(!resolve_condlist_exec(in, filename, fd))
|
if(!resolve_condlist_exec(in, ctx, fd))
|
||||||
{
|
{
|
||||||
resolve(in, (std::string*) &filename);
|
resolve(in, ctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -138,78 +138,68 @@ std::string random_string()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& filename)
|
void parse_exec(FILE* fd, parse_context ctx)
|
||||||
{
|
{
|
||||||
uint32_t i=skip_unread(in, size, 0);
|
ctx.i=skip_unread(ctx);
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
try
|
debashify_params debash_params;
|
||||||
|
list_t* t_lst=new list_t;
|
||||||
|
if(t_lst == nullptr)
|
||||||
|
throw std::runtime_error("Alloc error");
|
||||||
|
while(ctx.i<ctx.size)
|
||||||
{
|
{
|
||||||
#endif
|
auto pp=parse_condlist(ctx);
|
||||||
;
|
ctx=pp.second;
|
||||||
debashify_params debash_params;
|
if(ctx.has_errored)
|
||||||
list* t_lst=new list;
|
|
||||||
if(t_lst == nullptr)
|
|
||||||
throw std::runtime_error("Alloc error");
|
|
||||||
while(i<size)
|
|
||||||
{
|
{
|
||||||
auto pp=parse_condlist(in, size, i);
|
parse_list_until(ctx);
|
||||||
i=pp.second;
|
throw std::runtime_error("Aborting due to previous errors");
|
||||||
t_lst->add(pp.first);
|
}
|
||||||
if(g_resolve || g_include)
|
t_lst->add(pp.first);
|
||||||
|
if(g_resolve || g_include)
|
||||||
|
{
|
||||||
|
if(resolve_exec(t_lst->cls[0], ctx, fd))
|
||||||
{
|
{
|
||||||
if(resolve_exec(t_lst->cls[0], filename, fd))
|
t_lst->clear();
|
||||||
{
|
continue;
|
||||||
t_lst->clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(options["debashify"])
|
|
||||||
debashify(t_lst, &debash_params);
|
|
||||||
|
|
||||||
|
|
||||||
std::string gen=t_lst->generate(0);
|
|
||||||
t_lst->clear();
|
|
||||||
|
|
||||||
fprintf(fd, "%s", gen.c_str());
|
|
||||||
|
|
||||||
if(i < size)
|
|
||||||
{
|
|
||||||
if(in[i] == '#')
|
|
||||||
; // skip here
|
|
||||||
else if(is_in(in[i], COMMAND_SEPARATOR))
|
|
||||||
i++; // skip on next char
|
|
||||||
else if(is_in(in[i], CONTROL_END))
|
|
||||||
throw PARSE_ERROR(strf("Unexpected token: '%c'", in[i]), i);
|
|
||||||
|
|
||||||
i = skip_unread(in, size, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete t_lst;
|
if(options["debashify"])
|
||||||
#ifndef NO_PARSE_CATCH
|
debashify(t_lst, &debash_params);
|
||||||
}
|
|
||||||
catch(ztd::format_error& e)
|
|
||||||
{
|
std::string gen=t_lst->generate(0);
|
||||||
throw ztd::format_error(e.what(), filename, in, e.where());
|
t_lst->clear();
|
||||||
|
|
||||||
|
fprintf(fd, "%s", gen.c_str());
|
||||||
|
|
||||||
|
if(ctx.i < ctx.size)
|
||||||
|
{
|
||||||
|
if(ctx[ctx.i] == '#')
|
||||||
|
; // skip here
|
||||||
|
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||||
|
ctx.i++; // skip on next char
|
||||||
|
else if(is_in(ctx[ctx.i], CONTROL_END))
|
||||||
|
{
|
||||||
|
format_error(strf("Unexpected token: '%c'", ctx[ctx.i]), ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.i = skip_unread(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
delete t_lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
// char buf[1000] = {0};
|
|
||||||
// read(STDIN_FILENO, buf, 1000);
|
|
||||||
// std::cout << std::string(buf) << std::endl;
|
|
||||||
// std::cout << dup2(tfd, STDIN_FILENO) << std::endl;
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +224,7 @@ int wait_pid(pid_t pid)
|
||||||
return WEXITSTATUS(stat);
|
return WEXITSTATUS(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exec_process(std::string const& runtime, std::vector<std::string> const& args, std::string const& filecontents, std::string const& file)
|
int exec_process(std::string const& runtime, std::vector<std::string> const& args, parse_context ctx)
|
||||||
{
|
{
|
||||||
std::vector<std::string> strargs = split(runtime, " \t");
|
std::vector<std::string> strargs = split(runtime, " \t");
|
||||||
std::vector<char*> runargs;
|
std::vector<char*> runargs;
|
||||||
|
|
@ -246,19 +236,18 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
|
||||||
if(mkfifo(fifopath.c_str(), 0700)<0)
|
if(mkfifo(fifopath.c_str(), 0700)<0)
|
||||||
throw std::runtime_error("Cannot create fifo "+fifopath);
|
throw std::runtime_error("Cannot create fifo "+fifopath);
|
||||||
|
|
||||||
for(uint32_t i=0; i<strargs.size(); i++)
|
|
||||||
runargs.push_back((char*) strargs[i].c_str());
|
|
||||||
runargs.push_back((char*) fifopath.c_str());
|
|
||||||
for(uint32_t i=0; i<args.size(); i++)
|
|
||||||
runargs.push_back((char*) args[i].c_str());
|
|
||||||
runargs.push_back(NULL);
|
|
||||||
|
|
||||||
pid_t pid=0;
|
pid_t pid=0;
|
||||||
// std::string test="echo Hello world\nexit 10\n";
|
|
||||||
// fprintf(ffd, "%s\n",, test.c_str(), test.size());
|
|
||||||
FILE* ffd=0;
|
FILE* ffd=0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<strargs.size(); i++)
|
||||||
|
runargs.push_back((char*) strargs[i].c_str());
|
||||||
|
runargs.push_back((char*) fifopath.c_str());
|
||||||
|
for(uint32_t i=0; i<args.size(); i++)
|
||||||
|
runargs.push_back((char*) args[i].c_str());
|
||||||
|
runargs.push_back(NULL);
|
||||||
|
|
||||||
pid = forkexec(runargs[0], runargs.data());
|
pid = forkexec(runargs[0], runargs.data());
|
||||||
ffd = fopen(fifopath.c_str(), "w");
|
ffd = fopen(fifopath.c_str(), "w");
|
||||||
if(options["debashify"])
|
if(options["debashify"])
|
||||||
|
|
@ -268,14 +257,14 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
|
||||||
}
|
}
|
||||||
for(auto it: lxsh_extend_fcts)
|
for(auto it: lxsh_extend_fcts)
|
||||||
fprintf(ffd, "%s\n", it.second.code);
|
fprintf(ffd, "%s\n", it.second.code);
|
||||||
parse_exec(ffd, filecontents, file);
|
parse_exec(ffd, ctx);
|
||||||
}
|
}
|
||||||
catch(std::runtime_error& e)
|
catch(std::runtime_error& e)
|
||||||
{
|
{
|
||||||
fclose(ffd);
|
|
||||||
unlink(fifopath.c_str());
|
|
||||||
if(pid != 0)
|
if(pid != 0)
|
||||||
kill(pid, SIGINT);
|
kill(pid, SIGINT);
|
||||||
|
fclose(ffd);
|
||||||
|
unlink(fifopath.c_str());
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
172
src/generate.cpp
172
src/generate.cpp
|
|
@ -6,6 +6,9 @@
|
||||||
#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";
|
||||||
|
|
@ -19,7 +22,7 @@ std::string indented(std::string const& in, uint32_t ind)
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arg::generate(int ind)
|
std::string arg_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for(auto it: sa)
|
for(auto it: sa)
|
||||||
|
|
@ -29,7 +32,7 @@ std::string arg::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arglist::generate(int ind)
|
std::string arglist_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -44,7 +47,7 @@ std::string arglist::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pipeline::generate(int ind)
|
std::string pipeline_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -53,33 +56,48 @@ std::string pipeline::generate(int ind)
|
||||||
|
|
||||||
if(negated)
|
if(negated)
|
||||||
ret += "! ";
|
ret += "! ";
|
||||||
ret += cmds[0]->generate(ind);
|
|
||||||
|
if(bash_time)
|
||||||
|
ret += "time ";
|
||||||
|
|
||||||
|
ret += cmds[0]->generate(ind, ctx);
|
||||||
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
||||||
{
|
{
|
||||||
ret += opt_minify ? "|" : " | " ;
|
ret += opt_minify ? "|" : " | " ;
|
||||||
ret += cmds[i]->generate(ind);
|
ret += cmds[i]->generate(ind, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string condlist::generate(int ind)
|
std::string condlist_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(pls.size() <= 0)
|
if(pls.size() <= 0)
|
||||||
return "";
|
return "";
|
||||||
ret += pls[0]->generate(ind);
|
generate_context ctx;
|
||||||
|
ret += pls[0]->generate(ind, &ctx);
|
||||||
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
||||||
{
|
{
|
||||||
if(or_ops[i])
|
if(or_ops[i])
|
||||||
ret += opt_minify ? "||" : " || ";
|
ret += opt_minify ? "||" : " || ";
|
||||||
else
|
else
|
||||||
ret += opt_minify ? "&&" : " && ";
|
ret += opt_minify ? "&&" : " && ";
|
||||||
ret += pls[i+1]->generate(ind);
|
ret += pls[i+1]->generate(ind, &ctx);
|
||||||
}
|
}
|
||||||
|
prev_is_heredoc=false;
|
||||||
if(ret=="")
|
if(ret=="")
|
||||||
return "";
|
return "";
|
||||||
if(parallel)
|
if(ctx.here_document != nullptr)
|
||||||
|
{
|
||||||
|
if(parallel)
|
||||||
|
ret += '&';
|
||||||
|
ret += '\n';
|
||||||
|
ret += ctx.here_document->generate(0);
|
||||||
|
ret += '\n';
|
||||||
|
prev_is_heredoc=true;
|
||||||
|
}
|
||||||
|
else if(parallel)
|
||||||
{
|
{
|
||||||
ret += opt_minify ? "&" : " &\n";
|
ret += opt_minify ? "&" : " &\n";
|
||||||
}
|
}
|
||||||
|
|
@ -88,47 +106,58 @@ std::string condlist::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string list::generate(int ind, bool first_indent)
|
std::string list_t::generate(int ind, bool first_indent)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(cls.size() <= 0)
|
if(cls.size() <= 0)
|
||||||
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)
|
||||||
{
|
{
|
||||||
ret += indented(cls[i]->generate(ind), ind);
|
next = indented(cls[i]->generate(ind), ind);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
first_indent=true;
|
first_indent=true;
|
||||||
ret += cls[i]->generate(ind);
|
next = 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::generate(int ind)
|
std::string redirect_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret=op;
|
std::string ret=op;
|
||||||
if(target!=nullptr)
|
if(target!=nullptr)
|
||||||
{
|
{
|
||||||
if(!opt_minify)
|
std::string targetret=target->generate(0);
|
||||||
|
if(!(opt_minify && !is_in(targetret[0], "<>")))
|
||||||
ret += ' ';
|
ret += ' ';
|
||||||
ret += target->generate(0);
|
ret += targetret;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BLOCK
|
// BLOCK
|
||||||
|
|
||||||
std::string block::generate_redirs(int ind, std::string const& _str)
|
std::string block_t::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr)
|
||||||
{
|
{
|
||||||
std::string ret=" ";
|
std::string ret=" ";
|
||||||
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
||||||
for(auto it: redirs)
|
for(auto it: redirs)
|
||||||
{
|
{
|
||||||
|
if(ctx != nullptr && it->here_document != nullptr)
|
||||||
|
{
|
||||||
|
if(ctx->here_document != nullptr)
|
||||||
|
throw std::runtime_error("Unsupported generation of concurrent here documents");
|
||||||
|
ctx->here_document = it->here_document;
|
||||||
|
}
|
||||||
std::string _r = it->generate(0);
|
std::string _r = it->generate(0);
|
||||||
if(opt_minify && _r.size() > 0 && !is_num(_r[0]) && previous_isnt_num)
|
if(opt_minify && _r.size() > 0 && !is_num(_r[0]) && previous_isnt_num)
|
||||||
ret.pop_back(); // remove one space if possible
|
ret.pop_back(); // remove one space if possible
|
||||||
|
|
@ -139,7 +168,7 @@ std::string block::generate_redirs(int ind, std::string const& _str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string if_block::generate(int ind)
|
std::string if_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -169,17 +198,20 @@ std::string if_block::generate(int ind)
|
||||||
|
|
||||||
ret += indented("fi", ind);
|
ret += indented("fi", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string for_block::generate(int ind)
|
std::string for_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
ret += "for "+var->generate(ind);
|
ret += "for "+var->generate(ind);
|
||||||
if(iter != nullptr)
|
if(in_val) {
|
||||||
ret += " in " + iter->generate(ind);
|
ret += " in";
|
||||||
|
if(iter != nullptr)
|
||||||
|
ret += " " + 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);
|
||||||
|
|
@ -187,11 +219,11 @@ std::string for_block::generate(int ind)
|
||||||
|
|
||||||
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string while_block::generate(int ind)
|
std::string while_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -207,11 +239,11 @@ std::string while_block::generate(int ind)
|
||||||
|
|
||||||
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string subshell::generate(int ind)
|
std::string subshell_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// open subshell
|
// open subshell
|
||||||
|
|
@ -224,11 +256,11 @@ std::string subshell::generate(int ind)
|
||||||
// close subshell
|
// close subshell
|
||||||
ret += indented(")", ind);
|
ret += indented(")", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string shmain::generate(int ind)
|
std::string shmain::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
return this->generate(false, ind);
|
return this->generate(false, ind);
|
||||||
}
|
}
|
||||||
|
|
@ -241,11 +273,10 @@ std::string shmain::generate(bool print_shebang, int ind)
|
||||||
if( opt_minify && ret[ret.size()-1] == '\n')
|
if( opt_minify && ret[ret.size()-1] == '\n')
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string brace::generate(int ind)
|
std::string brace_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -253,11 +284,11 @@ std::string brace::generate(int ind)
|
||||||
ret += lst->generate(ind+1);
|
ret += lst->generate(ind+1);
|
||||||
ret += indented("}", ind);
|
ret += indented("}", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string function::generate(int ind)
|
std::string function_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// function definition
|
// function definition
|
||||||
|
|
@ -268,11 +299,11 @@ std::string function::generate(int ind)
|
||||||
ret += lst->generate(ind+1);
|
ret += lst->generate(ind+1);
|
||||||
ret += indented("}", ind);
|
ret += indented("}", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string case_block::generate(int ind)
|
std::string case_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += "case " + carg->generate(ind) + " in\n";
|
ret += "case " + carg->generate(ind) + " in\n";
|
||||||
|
|
@ -290,33 +321,51 @@ std::string case_block::generate(int ind)
|
||||||
// commands
|
// commands
|
||||||
ret += cs.second->generate(ind+1);
|
ret += cs.second->generate(ind+1);
|
||||||
// end of case: ;;
|
// end of case: ;;
|
||||||
if(opt_minify && ret[ret.size()-1] == '\n') // ;; can be right after command
|
if(opt_minify && !prev_is_heredoc && ret[ret.size()-1] == '\n') // ;; can be right after command
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += indented(";;\n", ind+1);
|
ret += indented(";;", ind+1);
|
||||||
|
if(!opt_minify)
|
||||||
|
ret+="\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove ;; from last case
|
// replace ;; from last case with \n
|
||||||
if(this->cases.size()>0 && opt_minify)
|
if(this->cases.size()>0 && opt_minify)
|
||||||
{
|
{
|
||||||
ret.erase(ret.size()-3, 2);
|
ret.pop_back();
|
||||||
|
ret.pop_back();
|
||||||
|
ret+='\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// close case
|
// close case
|
||||||
ind--;
|
ind--;
|
||||||
ret += indented("esac", ind);
|
ret += indented("esac", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmd::generate(int ind)
|
std::string cmd_t::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// var assigns
|
|
||||||
|
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
|
||||||
if(is_cmdvar)
|
if(is_cmdvar)
|
||||||
{
|
{
|
||||||
ret += args->generate(ind) + ' ';
|
ret += args->generate(ind) + ' ';
|
||||||
for(auto it: var_assigns)
|
for(auto it: cmd_var_assigns)
|
||||||
{
|
{
|
||||||
if(it.first != nullptr)
|
if(it.first != nullptr)
|
||||||
ret += it.first->generate(ind);
|
ret += it.first->generate(ind);
|
||||||
|
|
@ -328,17 +377,10 @@ std::string cmd::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto it: var_assigns)
|
// cmd itself
|
||||||
{
|
|
||||||
if(it.first != nullptr)
|
|
||||||
ret += it.first->generate(ind);
|
|
||||||
if(it.second != nullptr)
|
|
||||||
ret += it.second->generate(ind);
|
|
||||||
ret += ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -351,18 +393,28 @@ std::string cmd::generate(int ind)
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
std::string redirs = generate_redirs(ind, ret, ctx);
|
||||||
|
if(!has_args)
|
||||||
|
redirs.erase(redirs.begin());
|
||||||
|
ret += redirs;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUBARG
|
// SUBARG
|
||||||
|
|
||||||
std::string subshell_subarg::generate(int ind)
|
std::string subarg_subshell_t::generate(int ind)
|
||||||
{
|
{
|
||||||
return '$' + sbsh->generate(ind);
|
std::string r = sbsh->generate(ind);
|
||||||
|
if(backtick) {
|
||||||
|
r[0] = '`';
|
||||||
|
r[r.size()-1] = '`';
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return '$' + r;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string procsub_subarg::generate(int ind)
|
std::string subarg_procsub_t::generate(int ind)
|
||||||
{
|
{
|
||||||
if(is_output)
|
if(is_output)
|
||||||
return '>' + sbsh->generate(ind);
|
return '>' + sbsh->generate(ind);
|
||||||
|
|
@ -370,7 +422,7 @@ std::string procsub_subarg::generate(int ind)
|
||||||
return '<' + sbsh->generate(ind);
|
return '<' + sbsh->generate(ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arithmetic_subarg::generate(int ind)
|
std::string subarg_arithmetic_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += "$((";
|
ret += "$((";
|
||||||
|
|
@ -383,7 +435,7 @@ std::string arithmetic_subarg::generate(int ind)
|
||||||
|
|
||||||
// ARITHMETIC
|
// ARITHMETIC
|
||||||
|
|
||||||
std::string operation_arithmetic::generate(int ind)
|
std::string arithmetic_operation_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(precedence)
|
if(precedence)
|
||||||
|
|
@ -403,7 +455,7 @@ std::string operation_arithmetic::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parenthesis_arithmetic::generate(int ind)
|
std::string arithmetic_parenthesis_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += '(';
|
ret += '(';
|
||||||
|
|
@ -414,12 +466,12 @@ std::string parenthesis_arithmetic::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string subshell_arithmetic::generate(int ind)
|
std::string arithmetic_subshell_t::generate(int ind)
|
||||||
{
|
{
|
||||||
return '$' + sbsh->generate(ind);
|
return '$' + sbsh->generate(ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string variable_arithmetic::generate(int ind)
|
std::string arithmetic_variable_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret=var->generate(ind);
|
std::string ret=var->generate(ind);
|
||||||
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip)
|
if(is_num(ret[0]) || is_in(ret[0], SPECIAL_VARS) || var->is_manip)
|
||||||
|
|
@ -427,7 +479,7 @@ std::string variable_arithmetic::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string variable::generate(int ind)
|
std::string variable_t::generate(int ind)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(is_manip)
|
if(is_manip)
|
||||||
|
|
|
||||||
167
src/main.cpp
167
src/main.cpp
|
|
@ -1,12 +1,13 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <ztd/options.hpp>
|
#include <ztd/options.hpp>
|
||||||
#include <ztd/shell.hpp>
|
#include <ztd/shell.hpp>
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
#include "parse.hpp"
|
#include "parse.hpp"
|
||||||
|
|
@ -29,6 +30,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
bool optstop=false;
|
bool optstop=false;
|
||||||
|
|
||||||
|
shmain *sh=nullptr, *tsh=nullptr;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
args=options.process(argc, argv, {.stop_on_argument=true, .output_doubledash=true} );
|
args=options.process(argc, argv, {.stop_on_argument=true, .output_doubledash=true} );
|
||||||
|
|
@ -37,53 +39,49 @@ int main(int argc, char* argv[])
|
||||||
optstop=true;
|
optstop=true;
|
||||||
args.erase(args.begin());
|
args.erase(args.begin());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch(std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << e.what() << std::endl;
|
|
||||||
return ERR_OPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
oneshot_opt_process(argv[0]);
|
|
||||||
|
|
||||||
// resolve input
|
oneshot_opt_process(argv[0]);
|
||||||
std::string file;
|
|
||||||
if(args.size() > 0) // argument provided
|
// resolve input
|
||||||
{
|
std::string file;
|
||||||
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
|
if(args.size() > 0) // argument provided
|
||||||
{
|
{
|
||||||
file = "/dev/stdin";
|
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
|
||||||
|
{
|
||||||
|
file = "/dev/stdin";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file=args[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
file=args[0];
|
if(isatty(fileno(stdin))) // stdin is interactive
|
||||||
|
{
|
||||||
|
print_help(argv[0]);
|
||||||
|
return ERR_HELP;
|
||||||
|
}
|
||||||
|
else // is piped
|
||||||
|
{
|
||||||
|
file = "/dev/stdin";
|
||||||
|
args.push_back("/dev/stdin");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(isatty(fileno(stdin))) // stdin is interactive
|
|
||||||
{
|
|
||||||
print_help(argv[0]);
|
|
||||||
return ERR_HELP;
|
|
||||||
}
|
|
||||||
else // is piped
|
|
||||||
{
|
|
||||||
file = "/dev/stdin";
|
|
||||||
args.push_back("/dev/stdin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsing
|
// parsing
|
||||||
|
|
||||||
|
sh = new shmain;
|
||||||
|
|
||||||
shmain* sh = new shmain(new list);
|
|
||||||
shmain* tsh = nullptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool is_exec = false;
|
bool is_exec = false;
|
||||||
bool first_run = true;
|
bool first_run = true;
|
||||||
|
|
||||||
// do parsing
|
// do parsing
|
||||||
bool shebang_is_bin=false;
|
bool shebang_is_bin=false;
|
||||||
|
bool parse_bash=false;
|
||||||
|
parse_context ctx;
|
||||||
|
std::string binshebang;
|
||||||
for(uint32_t i=0 ; i<args.size() ; i++)
|
for(uint32_t i=0 ; i<args.size() ; i++)
|
||||||
{
|
{
|
||||||
std::string file = args[i];
|
std::string file = args[i];
|
||||||
|
|
@ -96,7 +94,24 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
first_run=false;
|
first_run=false;
|
||||||
// resolve shebang
|
// resolve shebang
|
||||||
shebang_is_bin = ( basename(argv[0]) == basename(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);
|
||||||
|
shebang_is_bin = ( basename(argv[0]) == binshebang );
|
||||||
|
parse_bash = (options["debashify"] || binshebang == "bash" || binshebang == "lxsh");
|
||||||
|
}
|
||||||
|
|
||||||
// detect if need execution
|
// detect if need execution
|
||||||
if(options['e'])
|
if(options['e'])
|
||||||
|
|
@ -113,36 +128,43 @@ int main(int argc, char* argv[])
|
||||||
throw std::runtime_error("Option -e must be before file");
|
throw std::runtime_error("Option -e must be before file");
|
||||||
|
|
||||||
if(shebang_is_bin) // enable debashify option
|
if(shebang_is_bin) // enable debashify option
|
||||||
|
{
|
||||||
|
shebang="#!/bin/sh";
|
||||||
options["debashify"].activated=true;
|
options["debashify"].activated=true;
|
||||||
|
}
|
||||||
|
|
||||||
oneshot_opt_process(argv[0]);
|
oneshot_opt_process(argv[0]);
|
||||||
get_opts();
|
get_opts();
|
||||||
|
|
||||||
}
|
}
|
||||||
// parse
|
// parse
|
||||||
g_origin=file;
|
|
||||||
if(!add_include(file))
|
if(!add_include(file))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ctx.data=filecontents.data();
|
||||||
|
|
||||||
|
ctx = make_context(filecontents, file, parse_bash);
|
||||||
if(is_exec)
|
if(is_exec)
|
||||||
{
|
{
|
||||||
if(options["debashify"])
|
delete sh;
|
||||||
shebang = "#!/bin/sh";
|
sh = nullptr;
|
||||||
if(options["debashify"] || basename(shebang) == "bash")
|
|
||||||
g_bash = true;
|
|
||||||
args.erase(args.begin());
|
args.erase(args.begin());
|
||||||
return exec_process(shebang.substr(2), args, filecontents, file);
|
return exec_process(shebang.substr(2), args, ctx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tsh = parse_text(filecontents, file);
|
auto pp = parse_text(ctx);
|
||||||
|
tsh = pp.first;
|
||||||
|
if(options["bash"])
|
||||||
|
tsh->shebang = "#!/usr/bin/env bash";
|
||||||
|
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";
|
||||||
|
|
||||||
/* mid processing */
|
/* mid processing */
|
||||||
// resolve/include
|
// resolve/include
|
||||||
if(g_include || g_resolve)
|
if(g_include || g_resolve)
|
||||||
resolve(tsh);
|
resolve(tsh, ctx);
|
||||||
|
|
||||||
// concatenate to main
|
// concatenate to main
|
||||||
sh->concat(tsh);
|
sh->concat(tsh);
|
||||||
|
|
@ -167,10 +189,6 @@ int main(int argc, char* argv[])
|
||||||
else if(options["list-cmd"])
|
else if(options["list-cmd"])
|
||||||
list_cmds(sh, regex_null);
|
list_cmds(sh, regex_null);
|
||||||
// output
|
// output
|
||||||
else if(options['J'])
|
|
||||||
{
|
|
||||||
std::cout << gen_json_struc(sh) << std::endl;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// post-listing modifiers
|
// post-listing modifiers
|
||||||
|
|
@ -185,18 +203,46 @@ 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;
|
||||||
if(options["minify-quotes"])
|
minify_generic(sh);
|
||||||
minify_quotes(sh);
|
}
|
||||||
if(options["minify-var"])
|
if(options['A']) {
|
||||||
minify_var( sh, re_var_exclude );
|
read_minmap(options['A'].argument, &varmap, &fctmap);
|
||||||
if(options["minify-fct"])
|
recurse(r_replace_var, sh, &varmap);
|
||||||
minify_fct( sh, re_fct_exclude );
|
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 );
|
||||||
|
}
|
||||||
// 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'];
|
||||||
|
|
@ -215,8 +261,7 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef NO_PARSE_CATCH
|
catch(format_error& e)
|
||||||
catch(ztd::format_error& e)
|
|
||||||
{
|
{
|
||||||
if(tsh != nullptr)
|
if(tsh != nullptr)
|
||||||
delete tsh;
|
delete tsh;
|
||||||
|
|
@ -224,16 +269,20 @@ int main(int argc, char* argv[])
|
||||||
printFormatError(e);
|
printFormatError(e);
|
||||||
return ERR_PARSE;
|
return ERR_PARSE;
|
||||||
}
|
}
|
||||||
#endif
|
catch(ztd::option_error& e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
return ERR_OPT;
|
||||||
|
}
|
||||||
catch(std::runtime_error& e)
|
catch(std::runtime_error& e)
|
||||||
{
|
{
|
||||||
if(tsh != nullptr)
|
if(tsh != nullptr)
|
||||||
delete tsh;
|
delete tsh;
|
||||||
delete sh;
|
if(sh != nullptr)
|
||||||
|
delete sh;
|
||||||
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;
|
||||||
|
|
|
||||||
593
src/minify.cpp
593
src/minify.cpp
|
|
@ -1,14 +1,15 @@
|
||||||
#include "minify.hpp"
|
#include "minify.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include "parse.hpp"
|
#include "parse.hpp"
|
||||||
#include "recursive.hpp"
|
#include "recursive.hpp"
|
||||||
#include "processing.hpp"
|
#include "processing.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
std::vector<subarg*> cmd::subarg_vars()
|
std::vector<subarg_t*> cmd_t::subarg_vars()
|
||||||
{
|
{
|
||||||
std::vector<subarg*> ret;
|
std::vector<subarg_t*> ret;
|
||||||
if(args==nullptr || args->size()<=0)
|
if(args==nullptr || args->size()<=0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
@ -16,7 +17,7 @@ std::vector<subarg*> cmd::subarg_vars()
|
||||||
{
|
{
|
||||||
for(uint32_t i=1; i<args->size(); i++)
|
for(uint32_t i=1; i<args->size(); i++)
|
||||||
{
|
{
|
||||||
arg* ta = args->args[i];
|
arg_t* ta = args->args[i];
|
||||||
if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string)
|
if(ta->sa.size() < 1 || ta->sa[0]->type != _obj::subarg_string)
|
||||||
continue;
|
continue;
|
||||||
if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0)))
|
if(ta->sa.size() >= 1 && is_varname(ta->sa[0]->generate(0)))
|
||||||
|
|
@ -34,19 +35,19 @@ bool r_replace_fct(_obj* in, strmap_t* fctmap)
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::block_function: {
|
case _obj::block_function: {
|
||||||
function* t = dynamic_cast<function*>(in);
|
function_t* t = dynamic_cast<function_t*>(in);
|
||||||
auto el=fctmap->find(t->name);
|
auto el=fctmap->find(t->name);
|
||||||
if(el!=fctmap->end())
|
if(el!=fctmap->end())
|
||||||
t->name = el->second;
|
t->name = el->second;
|
||||||
}; break;
|
}; break;
|
||||||
case _obj::block_cmd: {
|
case _obj::block_cmd: {
|
||||||
cmd* t = dynamic_cast<cmd*>(in);
|
cmd_t* t = dynamic_cast<cmd_t*>(in);
|
||||||
std::string cmdname = t->arg_string(0);
|
std::string cmdname = t->arg_string(0);
|
||||||
auto el=fctmap->find(cmdname);
|
auto el=fctmap->find(cmdname);
|
||||||
if(el!=fctmap->end())
|
if(el!=fctmap->end())
|
||||||
{
|
{
|
||||||
delete t->args->args[0];
|
delete t->args->args[0];
|
||||||
t->args->args[0] = new arg(el->second);
|
t->args->args[0] = new arg_t(el->second);
|
||||||
}
|
}
|
||||||
}; break;
|
}; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
@ -58,8 +59,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
|
||||||
{
|
{
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::_variable: {
|
case _obj::variable: {
|
||||||
variable* t = dynamic_cast<variable*>(in);
|
variable_t* t = dynamic_cast<variable_t*>(in);
|
||||||
auto el=varmap->find(t->varname);
|
auto el=varmap->find(t->varname);
|
||||||
if(el!=varmap->end())
|
if(el!=varmap->end())
|
||||||
t->varname = el->second;
|
t->varname = el->second;
|
||||||
|
|
@ -69,8 +70,20 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* escaped_char=" \\\t!\"()|&*?~";
|
const char* singlequote_escape_char=" \\\t!\"()|&*?~><#$";
|
||||||
const char* doublequote_escape_char=" \t'|&\\*?~";
|
const char* doublequote_escape_char=" \t'|&\\*()?~><#$";
|
||||||
|
uint32_t count_escape_char(std::string& in, uint32_t i, bool doublequote, std::string** estr, uint32_t* ei) {
|
||||||
|
if( ( doublequote && is_in(in[i], doublequote_escape_char) ) ||
|
||||||
|
( !doublequote && is_in(in[i], singlequote_escape_char) ) ) {
|
||||||
|
*estr = ∈
|
||||||
|
*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;
|
||||||
|
|
@ -78,7 +91,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], escaped_char))
|
else if(!doublequote && is_in(in[i], singlequote_escape_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;
|
||||||
|
|
@ -105,117 +118,216 @@ bool is_this_quote(char c, bool is_doublequote)
|
||||||
return c == '\'';
|
return c == '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_one_minify_quotes(string_subarg* in, bool prev_is_var, bool start_quoted)
|
bool is_varname(const char c) {
|
||||||
|
return is_alphanum(c) || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_minify_quotes(arg_t* in)
|
||||||
{
|
{
|
||||||
std::string& val = in->val;
|
auto t = in->sa.begin();
|
||||||
if(val.size() <= 1)
|
// global loop
|
||||||
return;
|
while(true)
|
||||||
if(start_quoted) // don't handle start quoted for now
|
|
||||||
return;
|
|
||||||
if(val[0] == '"' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
|
|
||||||
return;
|
|
||||||
if(val[0] == '\'' && prev_is_var && (is_alphanum(val[1]) || val[1] == '_') ) // removing quote would change varname: skip
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t i=0, j=0;
|
|
||||||
while( i < val.size() )
|
|
||||||
{
|
{
|
||||||
bool doublequote=false;
|
uint32_t i=0;
|
||||||
while(i<val.size() && !( val[i] == '\'' || val[i] == '"') )
|
// one iteration loop
|
||||||
|
while(true)
|
||||||
{
|
{
|
||||||
if(val[i] == '\\')
|
bool doublequote=false;
|
||||||
i++;
|
bool prev_is_var=false;
|
||||||
i++;
|
bool end_is_var=false;
|
||||||
}
|
bool has_substitution=false;
|
||||||
if(i>=val.size()) // end before finding quote: exit
|
std::string* strstart = nullptr;
|
||||||
return;
|
uint32_t quotestart=0;
|
||||||
if(val[i] == '"')
|
std::string* strend = nullptr;
|
||||||
doublequote=true;
|
uint32_t quoteend=0;
|
||||||
|
std::string* escapestr = nullptr;
|
||||||
j=i;
|
uint32_t escapepos=0;
|
||||||
i++;
|
uint32_t ce=0;
|
||||||
|
// loop to find start of quote
|
||||||
if(doublequote)
|
while(true)
|
||||||
{
|
|
||||||
while(i<val.size() && val[i] != '"')
|
|
||||||
{
|
{
|
||||||
if(val[i] == '\\')
|
// reached end: quit
|
||||||
|
if(t == in->sa.end())
|
||||||
|
return;
|
||||||
|
while((*t)->type != _obj::subarg_string)
|
||||||
|
{
|
||||||
|
// previous is alphanum var: removing quote can change varname
|
||||||
|
if((*t)->type == _obj::subarg_variable) {
|
||||||
|
subarg_variable_t* vs = dynamic_cast<subarg_variable_t*>(*t);
|
||||||
|
if(vs->var != nullptr && !vs->var->is_manip && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_num(vs->var->varname[0]) ) )
|
||||||
|
prev_is_var = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prev_is_var = false;
|
||||||
|
t++;
|
||||||
|
// quit when reached end of arg
|
||||||
|
if(t == in->sa.end())
|
||||||
|
return;
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
|
std::string& val = dynamic_cast<subarg_string_t*>(*t)->val;
|
||||||
|
// don't attempt if <= 2 chars
|
||||||
|
if(in->sa.size() == 1 && val.size() <= 2)
|
||||||
|
return;
|
||||||
|
while(i<val.size() && !( val[i] == '\'' || val[i] == '"') )
|
||||||
|
{
|
||||||
|
if(val[i] == '\\')
|
||||||
|
i++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// if found: break and go to next step
|
||||||
|
if(i<val.size()) {
|
||||||
|
if(val[i] == '"')
|
||||||
|
doublequote=true;
|
||||||
|
strstart=&val;
|
||||||
|
quotestart=i;
|
||||||
i++;
|
i++;
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if(i>=val.size()) // end before finding quote: exit
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while(i<val.size() && val[i] != '\'')
|
|
||||||
i++;
|
|
||||||
if(i>=val.size()) // end before finding quote: exit
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
uint32_t ce = count_escape_chars(val.substr(j+1, i-j-1), doublequote);
|
|
||||||
if(ce == 0)
|
|
||||||
{
|
|
||||||
val.erase(val.begin()+i);
|
|
||||||
val.erase(val.begin()+j);
|
|
||||||
}
|
|
||||||
else if(ce == 1) // only one char to escape: can save some space
|
|
||||||
{
|
|
||||||
val.erase(val.begin()+i);
|
|
||||||
val.erase(val.begin()+j);
|
|
||||||
uint32_t k;
|
|
||||||
if(doublequote)
|
|
||||||
{
|
|
||||||
for(k=j; k<i-1; k++)
|
|
||||||
{
|
|
||||||
if( is_in(val[k], doublequote_escape_char) )
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else
|
t++;
|
||||||
{
|
i=0;
|
||||||
for(k=j; k<i-1; k++)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
} // end of quote start loop
|
||||||
|
// loop to end of quote
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// reached end: quit
|
||||||
|
if(t == in->sa.end())
|
||||||
|
return;
|
||||||
|
while((*t)->type != _obj::subarg_string)
|
||||||
|
{
|
||||||
|
// previous is alphanum var: removing quote can change varname
|
||||||
|
if((*t)->type == _obj::subarg_variable) {
|
||||||
|
subarg_variable_t* vs = dynamic_cast<subarg_variable_t*>(*t);
|
||||||
|
if(vs->var != nullptr && !vs->var->is_manip && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_num(vs->var->varname[0]) ) )
|
||||||
|
end_is_var = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
end_is_var = false;
|
||||||
|
has_substitution=true;
|
||||||
|
t++;
|
||||||
|
// quit when reached end of arg
|
||||||
|
if(t == in->sa.end())
|
||||||
|
return;
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
|
std::string& val = dynamic_cast<subarg_string_t*>(*t)->val;
|
||||||
|
if(doublequote)
|
||||||
|
{
|
||||||
|
while(i<val.size() && val[i] != '"')
|
||||||
|
{
|
||||||
|
if(val[i] == '\\') {
|
||||||
|
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
|
||||||
|
}
|
||||||
|
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
|
||||||
|
}
|
||||||
|
if(i>=val.size()) { // end before finding quote: continue looping
|
||||||
|
t++;
|
||||||
|
i=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(i<val.size() && val[i] != '\'')
|
||||||
|
ce += count_escape_char(val, i++, doublequote, &escapestr, &escapepos);
|
||||||
|
if(i>=val.size()) { // end before finding quote: continue looping
|
||||||
|
t++;
|
||||||
|
i=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strend=&val;
|
||||||
|
quoteend=i;
|
||||||
|
break;
|
||||||
|
} // end of quote end loop
|
||||||
|
// has a substitution that can expand: don't dequote
|
||||||
|
if(!in->forcequoted && has_substitution) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// too many escapes: don't dequote
|
||||||
|
if(ce > 1) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// removing quotes changes variable name: don't dequote
|
||||||
|
if( ( prev_is_var && quotestart == 0 && strstart->size()>1 && is_varname((*strstart)[1]) ) ||
|
||||||
|
( end_is_var && quoteend == 0 && strend->size()>1 && is_varname((*strend)[1])) ) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
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 = dynamic_cast<arg*>(in);
|
arg_t* t = dynamic_cast<arg_t*>(in);
|
||||||
for(uint32_t i=0; i<t->sa.size(); i++)
|
do_minify_quotes(t);
|
||||||
{
|
|
||||||
if(t->sa[i]->type == _obj::subarg_string)
|
|
||||||
{
|
|
||||||
string_subarg* ss = dynamic_cast<string_subarg*>(t->sa[i]);
|
|
||||||
bool prev_is_var=false;
|
|
||||||
if(i>0 && t->sa[i-1]->type == _obj::subarg_variable)
|
|
||||||
{
|
|
||||||
variable_subarg* vs = dynamic_cast<variable_subarg*>(t->sa[i-1]);
|
|
||||||
if(vs->var != nullptr && vs->var->is_manip == false && vs->var->varname.size()>0 && !(is_in(vs->var->varname[0], SPECIAL_VARS) || is_alpha(vs->var->varname[0]) ) )
|
|
||||||
prev_is_var=true;
|
|
||||||
}
|
|
||||||
if(t->sa.size()==1 && (ss->val=="\"\"" || ss->val=="''") ) // single argument as "" or '': don't minify
|
|
||||||
continue;
|
|
||||||
do_one_minify_quotes(ss, prev_is_var, i>0 && t->sa[i-1]->quoted);
|
|
||||||
}
|
|
||||||
//if()
|
|
||||||
}
|
|
||||||
}; break;
|
}; break;
|
||||||
|
case _obj::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);
|
||||||
|
for(auto it: t->here_document->sa)
|
||||||
|
{
|
||||||
|
if(it->type!=_obj::subarg_string) {
|
||||||
|
recurse(r_minify_useless_quotes, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// don't recurse on the rest
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -282,47 +394,53 @@ strmap_t gen_minimal_map(countmap_t const& vars, set_t const& excluded)
|
||||||
|
|
||||||
// calls
|
// calls
|
||||||
|
|
||||||
void minify_var(_obj* in, std::regex const& exclude)
|
strmap_t minify_var(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
// countmap_t vars;
|
// countmap_t vars;
|
||||||
set_t excluded;
|
set_t excluded;
|
||||||
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, m_excluded_var);
|
varmap=gen_minimal_map(m_vars, excluded);
|
||||||
// perform replace
|
// perform replace
|
||||||
recurse(r_replace_var, in, &varmap);
|
recurse(r_replace_var, in, &varmap);
|
||||||
require_rescan_var();
|
require_rescan_var();
|
||||||
|
return varmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void minify_fct(_obj* in, std::regex const& exclude)
|
strmap_t minify_fct(_obj* in, std::regex const& exclude)
|
||||||
{
|
{
|
||||||
// countmap_t fcts, cmdmap;
|
// countmap_t fcts, cmdmap;
|
||||||
set_t allcmds, excluded, unsets;
|
set_t excluded, unsets;
|
||||||
strmap_t fctmap;
|
strmap_t fctmap;
|
||||||
// get fcts and cmds
|
// get fcts and cmds
|
||||||
fctmap_get(in, exclude);
|
fctcmdmap_get(in, exclude, regex_null);
|
||||||
cmdmap_get(in, regex_null);
|
|
||||||
recurse(r_get_unsets, in, &unsets);
|
recurse(r_get_unsets, in, &unsets);
|
||||||
// concatenate cmds and excluded commands
|
// concatenate cmds, excluded and reserved
|
||||||
allcmds=map_to_set(m_cmds);
|
excluded=map_to_set(m_cmds);
|
||||||
concat_sets(allcmds, m_excluded_fct);
|
exclude_sets(excluded, map_to_set(m_fcts));
|
||||||
concat_sets(allcmds, unsets);
|
concat_sets(excluded, m_excluded_fct);
|
||||||
|
concat_sets(excluded, unsets);
|
||||||
|
concat_sets(excluded, all_reserved_words);
|
||||||
// create mapping
|
// create mapping
|
||||||
fctmap=gen_minimal_map(m_fcts, allcmds);
|
m_fcts = combine_common(m_fcts, m_cmds);
|
||||||
|
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
|
||||||
fctmap_get(in, exclude);
|
fctcmdmap_get(in, exclude, regex_null);
|
||||||
cmdmap_get(in, regex_null);
|
|
||||||
// find unused fcts
|
// find unused fcts
|
||||||
for(auto it: m_fcts)
|
for(auto it: m_fcts)
|
||||||
{
|
{
|
||||||
|
|
@ -362,13 +480,248 @@ bool delete_unused_var(_obj* in, std::regex const& exclude)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void minify_quotes(_obj* in)
|
bool delete_unused_both(_obj* in, std::regex const& var_exclude, std::regex const& fct_exclude)
|
||||||
{
|
{
|
||||||
recurse(r_minify_useless_quotes, in);
|
set_t unused_var, unused_fct;
|
||||||
|
// 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_fct(in, fct_exclude) || delete_unused_var(in, var_exclude));
|
while(delete_unused_both(in, var_exclude, fct_exclude));
|
||||||
// keep deleting until both no function and no variables were deleted
|
// keep deleting until both no deletion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
src/options.cpp
118
src/options.cpp
|
|
@ -7,55 +7,56 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "g_version.h"
|
#include "g_version.h"
|
||||||
|
|
||||||
ztd::option_set options = gen_options();
|
|
||||||
bool opt_minify=false;
|
bool opt_minify=false;
|
||||||
|
|
||||||
|
ztd::option_set options( {
|
||||||
|
ztd::option("\r [Help]"),
|
||||||
|
ztd::option('h', "help", false, "Display this help message"),
|
||||||
|
ztd::option("version", false, "Display version"),
|
||||||
|
ztd::option("help-link-commands", false, "Print help for linker commands"),
|
||||||
|
ztd::option("help-extend-fcts", false, "Print help for lxsh extension functions"),
|
||||||
|
ztd::option("\r [Output]"),
|
||||||
|
ztd::option('o', "output", true , "Output result script to file", "file"),
|
||||||
|
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
||||||
|
ztd::option('e', "exec", false, "Directly execute script"),
|
||||||
|
ztd::option("no-shebang", false, "Don't output shebang"),
|
||||||
|
ztd::option('P', "map", true , "Output var and fct minify map to given file", "file"),
|
||||||
|
#ifdef DEBUG_MODE
|
||||||
|
ztd::option("\r [Debugging]"),
|
||||||
|
ztd::option('J', "json", false, "Output the json structure"),
|
||||||
|
#endif
|
||||||
|
ztd::option("\r [Processing]"),
|
||||||
|
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
||||||
|
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-var --minify-fct --remove-unused"),
|
||||||
|
ztd::option('A', "apply-map", true , "Apply var/fct minify map from given file", "file"),
|
||||||
|
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
|
||||||
|
ztd::option('I', "no-include", false, "Don't resolve %include commands"),
|
||||||
|
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
||||||
|
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
||||||
|
ztd::option("bash", false, "Force bash parsing"),
|
||||||
|
ztd::option("lxsh", false, "Force lxsh parsing"),
|
||||||
|
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
||||||
|
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
||||||
|
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
||||||
|
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("no-exclude-reserved",false, "Don't exclude reserved variables"),
|
||||||
|
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-def", false, "List all variables set 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("\r [Function processing]"),
|
||||||
|
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing, separated by spaces", "list"),
|
||||||
|
ztd::option("minify-fct", false, "Minify function names"),
|
||||||
|
ztd::option("list-fct", false, "List all functions defined in the script")
|
||||||
|
} );
|
||||||
|
|
||||||
bool g_cd=false;
|
bool g_cd=false;
|
||||||
bool g_include=true;
|
bool g_include=true;
|
||||||
bool g_resolve=true;
|
bool g_resolve=true;
|
||||||
bool g_shebang=true;
|
bool g_shebang=true;
|
||||||
|
|
||||||
ztd::option_set gen_options()
|
|
||||||
{
|
|
||||||
ztd::option_set ret;
|
|
||||||
ret.add(
|
|
||||||
ztd::option("\r [Help]"),
|
|
||||||
ztd::option('h', "help", false, "Display this help message"),
|
|
||||||
ztd::option("version", false, "Display version"),
|
|
||||||
ztd::option("help-link-commands", false, "Print help for linker commands"),
|
|
||||||
ztd::option("help-extend-fcts", false, "Print help for lxsh extension functions"),
|
|
||||||
ztd::option("\r [Output]"),
|
|
||||||
ztd::option('o', "output", true , "Output result script to file", "file"),
|
|
||||||
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
|
||||||
ztd::option('e', "exec", false, "Directly execute script"),
|
|
||||||
ztd::option("no-shebang", false, "Don't output shebang"),
|
|
||||||
ztd::option('J', "json", false, "Output the json structure"),
|
|
||||||
ztd::option("\r [Processing]"),
|
|
||||||
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
|
||||||
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
|
|
||||||
ztd::option("minify-quotes", false, "Remove unnecessary quotes"),
|
|
||||||
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
|
|
||||||
ztd::option('I', "no-include", false, "Don't resolve %include commands"),
|
|
||||||
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
|
||||||
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
|
||||||
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
|
||||||
ztd::option("\r [var/fct processing]"),
|
|
||||||
ztd::option("minify-var", false, "Minify variable names"),
|
|
||||||
ztd::option("minify-fct", false, "Minify function names"),
|
|
||||||
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
|
|
||||||
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
|
|
||||||
ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"),
|
|
||||||
ztd::option("list-var", false, "List all variables set and invoked in the script"),
|
|
||||||
ztd::option("list-var-def", false, "List all variables set in the script"),
|
|
||||||
ztd::option("list-var-call", false, "List all variables invoked in the script"),
|
|
||||||
ztd::option("list-fct", false, "List all functions defined in the script"),
|
|
||||||
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
|
||||||
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
|
||||||
ztd::option("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference")
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_opts()
|
void get_opts()
|
||||||
{
|
{
|
||||||
g_cd=!options['C'].activated;
|
g_cd=!options['C'].activated;
|
||||||
|
|
@ -73,38 +74,43 @@ 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()
|
||||||
{
|
{
|
||||||
ztd::option_set opts;
|
return std::vector<ztd::option>({
|
||||||
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()
|
||||||
{
|
{
|
||||||
ztd::option_set opts;
|
return std::vector<ztd::option>({
|
||||||
opts.add(
|
|
||||||
ztd::option('C', false, "Don't cd to folder this file is in"),
|
ztd::option('C', false, "Don't cd to folder this file is in"),
|
||||||
ztd::option('f', false, "Ignore non-zero return values")
|
ztd::option('f', false, "Ignore non-zero return values")
|
||||||
);
|
});
|
||||||
return opts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_help(const char* arg0)
|
void print_help(const char* arg0)
|
||||||
{
|
{
|
||||||
printf("%s [options] <file> [arg...]\n", arg0);
|
printf("%s [options] <file> [arg...]\n", arg0);
|
||||||
printf("Link extended shell\n");
|
printf("Extended shell linker\n");
|
||||||
printf("Include files and resolve commands on build time\n");
|
printf("Include files, resolve commands on build time, process and minify shell code\n");
|
||||||
printf("See --help-commands for help on linker commands\n");
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
options.print_help(4,25);
|
options.print_help(4,25);
|
||||||
|
|
@ -130,7 +136,7 @@ void print_resolve_help()
|
||||||
printf("Execute shell command and substitute output, from folder of current file\n");
|
printf("Execute shell command and substitute output, from folder of current file\n");
|
||||||
printf(" - Default behaviour is to parse contents as shell code\n");
|
printf(" - Default behaviour is to parse contents as shell code\n");
|
||||||
printf(" - Fails if return value is not 0. Can be ignored with -f\n");
|
printf(" - Fails if return value is not 0. Can be ignored with -f\n");
|
||||||
printf(" - `%%include` inside substitutions replaces the substitution and puts raw response\n");
|
printf(" - `%%resolve` inside substitutions replaces the substitution and puts raw response\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
ztd::option_set opts=create_resolve_opts();
|
ztd::option_set opts=create_resolve_opts();
|
||||||
|
|
|
||||||
2478
src/parse.cpp
2478
src/parse.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,10 @@
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "shellcode.hpp"
|
#include "shellcode.hpp"
|
||||||
#include "struc_helper.hpp"
|
#include "struc_helper.hpp"
|
||||||
|
#include "options.hpp"
|
||||||
|
#include "minify.hpp"
|
||||||
|
|
||||||
|
#include "errcodes.h"
|
||||||
|
|
||||||
// Global regex
|
// Global regex
|
||||||
|
|
||||||
|
|
@ -23,7 +27,6 @@ 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()
|
||||||
|
|
@ -59,12 +62,7 @@ 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;
|
countmap_t ret = a;
|
||||||
for(auto it: a)
|
|
||||||
{
|
|
||||||
if(!ret.insert( it ).second)
|
|
||||||
ret[it.first] += it.second;
|
|
||||||
}
|
|
||||||
for(auto it: b)
|
for(auto it: b)
|
||||||
{
|
{
|
||||||
if(!ret.insert( it ).second)
|
if(!ret.insert( it ).second)
|
||||||
|
|
@ -73,6 +71,19 @@ countmap_t combine_maps(countmap_t const& a, countmap_t const& b)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(t!=b.end())
|
||||||
|
ret[it.first] += t->second;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void list_map(countmap_t const& map)
|
void list_map(countmap_t const& map)
|
||||||
{
|
{
|
||||||
uint32_t max=0;
|
uint32_t max=0;
|
||||||
|
|
@ -144,7 +155,7 @@ std::string get_varname(std::string const& in)
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_varname(arg* in)
|
std::string get_varname(arg_t* in)
|
||||||
{
|
{
|
||||||
if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string)
|
if(in->sa.size() < 1 || in->sa[0]->type != _obj::subarg_string)
|
||||||
return "";
|
return "";
|
||||||
|
|
@ -156,15 +167,15 @@ std::string get_varname(arg* in)
|
||||||
|
|
||||||
bool cmd_is_argvar(std::string const& in)
|
bool cmd_is_argvar(std::string const& in)
|
||||||
{
|
{
|
||||||
return is_in_vector(in, posix_cmdvar) || is_in_vector(in, bash_cmdvar);
|
return is_in_set(in, posix_cmdvar) || is_in_set(in, bash_cmdvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmd::is_argvar()
|
bool cmd_t::is_argvar()
|
||||||
{
|
{
|
||||||
return is_cmdvar;
|
return is_cmdvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmd::is(std::string const& in)
|
bool cmd_t::is(std::string const& in)
|
||||||
{
|
{
|
||||||
return in == this->arg_string(0);
|
return in == this->arg_string(0);
|
||||||
}
|
}
|
||||||
|
|
@ -202,6 +213,39 @@ 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)
|
||||||
|
|
@ -241,28 +285,53 @@ void add_unset_variables(shmain* sh, std::regex const& exclude)
|
||||||
varmap_get(sh, exclude);
|
varmap_get(sh, exclude);
|
||||||
if(m_vars.size()>0)
|
if(m_vars.size()>0)
|
||||||
{
|
{
|
||||||
cmd* unset_cmd = new cmd;
|
cmd_t* unset_cmd = new cmd_t;
|
||||||
unset_cmd->add(new arg("unset"));
|
unset_cmd->add(new arg_t("unset"));
|
||||||
unset_cmd->is_cmdvar=true;
|
unset_cmd->is_cmdvar=true;
|
||||||
for(auto it: m_vars)
|
for(auto it: m_vars)
|
||||||
{
|
{
|
||||||
unset_cmd->var_assigns.push_back(std::make_pair(new variable(it.first), nullptr));
|
unset_cmd->cmd_var_assigns.push_back(std::make_pair(new variable_t(it.first), nullptr));
|
||||||
}
|
}
|
||||||
condlist* cl = new condlist(unset_cmd);
|
condlist_t* cl = new condlist_t(unset_cmd);
|
||||||
sh->lst->cls.insert(sh->lst->cls.begin(), cl);
|
sh->lst->cls.insert(sh->lst->cls.begin(), cl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = dynamic_cast<variable*>(in);
|
variable_t* t = dynamic_cast<variable_t*>(in);
|
||||||
if(t->definition)
|
if(t->definition)
|
||||||
{
|
{
|
||||||
if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
|
if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
|
||||||
|
|
@ -284,10 +353,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 = dynamic_cast<cmd*>(in);
|
cmd_t* t = dynamic_cast<cmd_t*>(in);
|
||||||
if(t->is("unset"))
|
if(t->is("unset"))
|
||||||
{
|
{
|
||||||
for(auto it: t->var_assigns)
|
for(auto it: t->cmd_var_assigns)
|
||||||
{
|
{
|
||||||
if(it.first != nullptr)
|
if(it.first != nullptr)
|
||||||
unsets->insert(it.first->varname);
|
unsets->insert(it.first->varname);
|
||||||
|
|
@ -304,7 +373,7 @@ bool r_get_cmd(_obj* in, countmap_t* all_cmds)
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::block_cmd: {
|
case _obj::block_cmd: {
|
||||||
cmd* t = dynamic_cast<cmd*>(in);
|
cmd_t* t = dynamic_cast<cmd_t*>(in);
|
||||||
std::string cmdname = t->arg_string(0);
|
std::string cmdname = t->arg_string(0);
|
||||||
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
|
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
|
||||||
(*all_cmds)[cmdname]++;
|
(*all_cmds)[cmdname]++;
|
||||||
|
|
@ -319,7 +388,7 @@ bool r_get_fct(_obj* in, countmap_t* fct_map)
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::block_function: {
|
case _obj::block_function: {
|
||||||
function* t = dynamic_cast<function*>(in);
|
function_t* t = dynamic_cast<function_t*>(in);
|
||||||
if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
|
if(!fct_map->insert( std::make_pair(t->name, 1) ).second)
|
||||||
(*fct_map)[t->name]++;
|
(*fct_map)[t->name]++;
|
||||||
}; break;
|
}; break;
|
||||||
|
|
@ -328,20 +397,35 @@ 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 = dynamic_cast<list*>(in);
|
list_t* t = dynamic_cast<list_t*>(in);
|
||||||
for(uint32_t i=0; i<t->cls.size(); i++)
|
for(uint32_t i=0; i<t->cls.size(); i++)
|
||||||
{
|
{
|
||||||
block* tb = t->cls[i]->first_block();
|
block_t* tb = t->cls[i]->first_block();
|
||||||
if(tb != nullptr && tb->type == _obj::block_function)
|
if(tb != nullptr && tb->type == _obj::block_function)
|
||||||
{
|
{
|
||||||
function* fc = dynamic_cast<function*>(tb);
|
function_t* fc = dynamic_cast<function_t*>(tb);
|
||||||
if(fcts->find(fc->name)!=fcts->end())
|
if(fcts->find(fc->name)!=fcts->end())
|
||||||
{
|
{
|
||||||
delete t->cls[i];
|
delete t->cls[i];
|
||||||
|
|
@ -360,16 +444,16 @@ bool r_delete_var(_obj* in, set_t* vars)
|
||||||
{
|
{
|
||||||
switch(in->type)
|
switch(in->type)
|
||||||
{
|
{
|
||||||
case _obj::_list: {
|
case _obj::list: {
|
||||||
list* t = dynamic_cast<list*>(in);
|
list_t* t = dynamic_cast<list_t*>(in);
|
||||||
for(uint32_t i=0; i<t->cls.size(); i++)
|
for(uint32_t i=0; i<t->cls.size(); i++)
|
||||||
{
|
{
|
||||||
block* tb = t->cls[i]->first_block();
|
block_t* tb = t->cls[i]->first_block();
|
||||||
bool to_delete=false;
|
bool to_delete=false;
|
||||||
bool has_deleted=false;
|
bool has_deleted=false;
|
||||||
if(tb != nullptr && tb->type == _obj::block_cmd)
|
if(tb != nullptr && tb->type == _obj::block_cmd)
|
||||||
{
|
{
|
||||||
cmd* c = dynamic_cast<cmd*>(tb);
|
cmd_t* c = dynamic_cast<cmd_t*>(tb);
|
||||||
|
|
||||||
for(uint32_t j=0; j<c->var_assigns.size(); j++)
|
for(uint32_t j=0; j<c->var_assigns.size(); j++)
|
||||||
{
|
{
|
||||||
|
|
@ -387,6 +471,22 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -394,6 +494,8 @@ 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;
|
||||||
|
|
@ -401,6 +503,13 @@ 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;
|
||||||
|
|
@ -415,11 +524,75 @@ std::set<std::string> find_lxsh_commands(shmain* sh)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::string> get_processors(std::string const& in)
|
||||||
|
{
|
||||||
|
std::set<std::string> ret;
|
||||||
|
if(in.size()>2 && in[0] == '\'' && in[in.size()-1] == '\'')
|
||||||
|
{
|
||||||
|
uint32_t i=1;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
std::string ln = in.substr(i, in.find('\n', i)-i);
|
||||||
|
if(ln.size()>1 && ln[0] == '#' && is_alphanum(ln[1]))
|
||||||
|
{
|
||||||
|
i+=ln.size();
|
||||||
|
ret.insert(get_word(make_context(ln.substr(1)), SEPARATORS).first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r_do_string_processor(_obj* in)
|
||||||
|
{
|
||||||
|
if(in->type == _obj::subarg_string)
|
||||||
|
{
|
||||||
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(in);
|
||||||
|
auto v = get_processors(t->val);
|
||||||
|
if(v.find("LXSH_PARSE_MINIFY") != v.end())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string stringcode = t->val.substr(1, t->val.size()-2);
|
||||||
|
shmain* tsh = parse_text( stringcode ).first;
|
||||||
|
require_rescan_all();
|
||||||
|
if(options["remove-unused"])
|
||||||
|
delete_unused( tsh, re_var_exclude, re_fct_exclude );
|
||||||
|
if(options["minify"])
|
||||||
|
minify_generic(tsh);
|
||||||
|
if(options["minify-var"])
|
||||||
|
minify_var( tsh, re_var_exclude );
|
||||||
|
if(options["minify-fct"])
|
||||||
|
minify_fct( tsh, re_fct_exclude );
|
||||||
|
require_rescan_all();
|
||||||
|
t->val='\'' + tsh->generate(false, 0) + '\'';
|
||||||
|
}
|
||||||
|
catch(format_error& e) // if fail: skip processing
|
||||||
|
{
|
||||||
|
std::cerr << "Exception caused in string processing LXSH_PARSE_MINIFY\n";
|
||||||
|
printFormatError(e);
|
||||||
|
exit(ERR_RUNTIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_processors(_obj* 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(in, "\"", "\\\"") + '"';
|
return '"' + stringReplace(stringReplace(stringReplace(in, "\\", "\\\\"), "\"", "\\\""), "\n", "\\n") + '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
@ -461,9 +634,9 @@ std::string gen_json_struc(_obj* o)
|
||||||
std::vector<std::pair<std::string,std::string>> vec;
|
std::vector<std::pair<std::string,std::string>> vec;
|
||||||
switch(o->type)
|
switch(o->type)
|
||||||
{
|
{
|
||||||
case _obj::_variable :
|
case _obj::variable :
|
||||||
{
|
{
|
||||||
variable* t = dynamic_cast<variable*>(o);
|
variable_t* t = dynamic_cast<variable_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("variable") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname)));
|
vec.push_back(std::make_pair(quote_string("varname"), quote_string(t->varname)));
|
||||||
vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition)));
|
vec.push_back(std::make_pair(quote_string("definition"), boolstring(t->definition)));
|
||||||
|
|
@ -473,27 +646,29 @@ std::string gen_json_struc(_obj* o)
|
||||||
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
|
vec.push_back(std::make_pair(quote_string("manip"), gen_json_struc(t->manip) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_redirect :
|
case _obj::redirect :
|
||||||
{
|
{
|
||||||
redirect* t = dynamic_cast<redirect*>(o);
|
redirect_t* t = dynamic_cast<redirect_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("redirect") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op)));
|
vec.push_back(std::make_pair(quote_string("op"), quote_string(t->op)));
|
||||||
vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target)));
|
vec.push_back(std::make_pair(quote_string("target"), gen_json_struc(t->target)));
|
||||||
|
vec.push_back(std::make_pair(quote_string("here_document"), gen_json_struc(t->here_document)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_arg :
|
case _obj::arg :
|
||||||
{
|
{
|
||||||
arg* t = dynamic_cast<arg*>(o);
|
arg_t* t = dynamic_cast<arg_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arg") ) );
|
||||||
|
vec.push_back(std::make_pair(quote_string("forcequoted"), boolstring(t->forcequoted)));
|
||||||
std::vector<std::string> tvec;
|
std::vector<std::string> tvec;
|
||||||
for(auto it: t->sa)
|
for(auto it: t->sa)
|
||||||
tvec.push_back(gen_json_struc(it));
|
tvec.push_back(gen_json_struc(it));
|
||||||
vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec)));
|
vec.push_back(std::make_pair(quote_string("sa"), gen_json(tvec)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_arglist :
|
case _obj::arglist :
|
||||||
{
|
{
|
||||||
arglist* t = dynamic_cast<arglist*>(o);
|
arglist_t* t = dynamic_cast<arglist_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arglist") ) );
|
||||||
std::vector<std::string> tvec;
|
std::vector<std::string> tvec;
|
||||||
for(auto it: t->args)
|
for(auto it: t->args)
|
||||||
|
|
@ -501,9 +676,9 @@ std::string gen_json_struc(_obj* o)
|
||||||
vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec)));
|
vec.push_back(std::make_pair(quote_string("args"), gen_json(tvec)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_pipeline :
|
case _obj::pipeline :
|
||||||
{
|
{
|
||||||
pipeline* t = dynamic_cast<pipeline*>(o);
|
pipeline_t* t = dynamic_cast<pipeline_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("pipeline") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) );
|
vec.push_back(std::make_pair(quote_string("negated"), boolstring(t->negated) ) );
|
||||||
std::vector<std::string> tvec;
|
std::vector<std::string> tvec;
|
||||||
|
|
@ -512,9 +687,9 @@ std::string gen_json_struc(_obj* o)
|
||||||
vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec)));
|
vec.push_back(std::make_pair(quote_string("cmds"), gen_json(tvec)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_condlist :
|
case _obj::condlist :
|
||||||
{
|
{
|
||||||
condlist* t = dynamic_cast<condlist*>(o);
|
condlist_t* t = dynamic_cast<condlist_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("condlist") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) );
|
vec.push_back(std::make_pair(quote_string("parallel"), boolstring(t->parallel) ) );
|
||||||
std::vector<std::string> tvec;
|
std::vector<std::string> tvec;
|
||||||
|
|
@ -530,9 +705,9 @@ std::string gen_json_struc(_obj* o)
|
||||||
vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec)));
|
vec.push_back(std::make_pair(quote_string("or_ops"), gen_json(ttvec)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::_list :
|
case _obj::list :
|
||||||
{
|
{
|
||||||
list* t = dynamic_cast<list*>(o);
|
list_t* t = dynamic_cast<list_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("list") ) );
|
||||||
std::vector<std::string> tvec;
|
std::vector<std::string> tvec;
|
||||||
for(auto it: t->cls)
|
for(auto it: t->cls)
|
||||||
|
|
@ -542,7 +717,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_subshell :
|
case _obj::block_subshell :
|
||||||
{
|
{
|
||||||
subshell* t = dynamic_cast<subshell*>(o);
|
subshell_t* t = dynamic_cast<subshell_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subshell") ) );
|
||||||
|
|
||||||
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
|
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
|
||||||
|
|
@ -556,7 +731,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_brace :
|
case _obj::block_brace :
|
||||||
{
|
{
|
||||||
brace* t = dynamic_cast<brace*>(o);
|
brace_t* t = dynamic_cast<brace_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("brace") ) );
|
||||||
|
|
||||||
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
|
vec.push_back(std::make_pair(quote_string("lst"), gen_json_struc(t->lst)));
|
||||||
|
|
@ -585,7 +760,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_function :
|
case _obj::block_function :
|
||||||
{
|
{
|
||||||
function* t = dynamic_cast<function*>(o);
|
function_t* t = dynamic_cast<function_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("function") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) );
|
vec.push_back(std::make_pair(quote_string("name"), quote_string(t->name) ) );
|
||||||
|
|
||||||
|
|
@ -600,7 +775,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_cmd :
|
case _obj::block_cmd :
|
||||||
{
|
{
|
||||||
cmd* t = dynamic_cast<cmd*>(o);
|
cmd_t* t = dynamic_cast<cmd_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("cmd") ) );
|
||||||
|
|
||||||
vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args)));
|
vec.push_back(std::make_pair(quote_string("args"), gen_json_struc(t->args)));
|
||||||
|
|
@ -615,6 +790,15 @@ 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)
|
||||||
|
|
@ -625,7 +809,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_case :
|
case _obj::block_case :
|
||||||
{
|
{
|
||||||
case_block* t = dynamic_cast<case_block*>(o);
|
case_t* t = dynamic_cast<case_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("case") ) );
|
||||||
|
|
||||||
vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg)));
|
vec.push_back(std::make_pair(quote_string("carg"), gen_json_struc(t->carg)));
|
||||||
|
|
@ -654,7 +838,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_if :
|
case _obj::block_if :
|
||||||
{
|
{
|
||||||
if_block* t = dynamic_cast<if_block*>(o);
|
if_t* t = dynamic_cast<if_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("if") ) );
|
||||||
|
|
||||||
std::vector<std::string> condblocks;
|
std::vector<std::string> condblocks;
|
||||||
|
|
@ -679,7 +863,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_for :
|
case _obj::block_for :
|
||||||
{
|
{
|
||||||
for_block* t = dynamic_cast<for_block*>(o);
|
for_t* t = dynamic_cast<for_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("for") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var)));
|
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var)));
|
||||||
vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter)));
|
vec.push_back(std::make_pair(quote_string("iter"), gen_json_struc(t->iter)));
|
||||||
|
|
@ -694,7 +878,7 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::block_while :
|
case _obj::block_while :
|
||||||
{
|
{
|
||||||
while_block* t = dynamic_cast<while_block*>(o);
|
while_t* t = dynamic_cast<while_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("while") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) );
|
vec.push_back(std::make_pair(quote_string("cond"), gen_json_struc(t->cond) ) );
|
||||||
vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) );
|
vec.push_back(std::make_pair(quote_string("ops"), gen_json_struc(t->ops) ) );
|
||||||
|
|
@ -708,21 +892,21 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::subarg_variable :
|
case _obj::subarg_variable :
|
||||||
{
|
{
|
||||||
variable_subarg* t = dynamic_cast<variable_subarg*>(o);
|
subarg_variable_t* t = dynamic_cast<subarg_variable_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_variable") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
|
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_subshell :
|
case _obj::subarg_subshell :
|
||||||
{
|
{
|
||||||
subshell_subarg* t = dynamic_cast<subshell_subarg*>(o);
|
subarg_subshell_t* t = dynamic_cast<subarg_subshell_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_subshell") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_procsub :
|
case _obj::subarg_procsub :
|
||||||
{
|
{
|
||||||
procsub_subarg* t = dynamic_cast<procsub_subarg*>(o);
|
subarg_procsub_t* t = dynamic_cast<subarg_procsub_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_procsub") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) );
|
vec.push_back(std::make_pair(quote_string("is_output"), boolstring(t->is_output) ) );
|
||||||
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
||||||
|
|
@ -730,35 +914,35 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::subarg_arithmetic :
|
case _obj::subarg_arithmetic :
|
||||||
{
|
{
|
||||||
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
|
subarg_arithmetic_t* t = dynamic_cast<subarg_arithmetic_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_arithmetic") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) );
|
vec.push_back(std::make_pair(quote_string("arith"), gen_json_struc(t->arith) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::subarg_string :
|
case _obj::subarg_string :
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(o);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("subarg_string") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
|
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_variable :
|
case _obj::arithmetic_variable :
|
||||||
{
|
{
|
||||||
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o);
|
arithmetic_variable_t* t = dynamic_cast<arithmetic_variable_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_variable") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
|
vec.push_back(std::make_pair(quote_string("var"), gen_json_struc(t->var) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_subshell :
|
case _obj::arithmetic_subshell :
|
||||||
{
|
{
|
||||||
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o);
|
arithmetic_subshell_t* t = dynamic_cast<arithmetic_subshell_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_subshell") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
vec.push_back(std::make_pair(quote_string("sbsh"), gen_json_struc(t->sbsh) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_operation :
|
case _obj::arithmetic_operation :
|
||||||
{
|
{
|
||||||
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
|
arithmetic_operation_t* t = dynamic_cast<arithmetic_operation_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_operation") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) );
|
vec.push_back(std::make_pair(quote_string("val1"), gen_json_struc(t->val1) ) );
|
||||||
vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) );
|
vec.push_back(std::make_pair(quote_string("val2"), gen_json_struc(t->val2) ) );
|
||||||
|
|
@ -766,14 +950,14 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_parenthesis :
|
case _obj::arithmetic_parenthesis :
|
||||||
{
|
{
|
||||||
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
|
arithmetic_parenthesis_t* t = dynamic_cast<arithmetic_parenthesis_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_parenthesis") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) );
|
vec.push_back(std::make_pair(quote_string("val"), gen_json_struc(t->val) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _obj::arithmetic_number :
|
case _obj::arithmetic_number :
|
||||||
{
|
{
|
||||||
number_arithmetic* t = dynamic_cast<number_arithmetic*>(o);
|
arithmetic_number_t* t = dynamic_cast<arithmetic_number_t*>(o);
|
||||||
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) );
|
vec.push_back(std::make_pair(quote_string("type"), quote_string("arithmetic_number") ) );
|
||||||
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
|
vec.push_back(std::make_pair(quote_string("val"), quote_string(t->val) ) );
|
||||||
break;
|
break;
|
||||||
|
|
@ -781,3 +965,4 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
return gen_json(vec);
|
return gen_json(vec);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
160
src/resolve.cpp
160
src/resolve.cpp
|
|
@ -34,7 +34,6 @@ bool add_include(std::string const& file)
|
||||||
if(it == truepath)
|
if(it == truepath)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// std::cout << truepath << std::endl;
|
|
||||||
included.push_back(truepath);
|
included.push_back(truepath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +59,7 @@ void _cd(std::string const& dir)
|
||||||
// -- COMMANDS --
|
// -- COMMANDS --
|
||||||
|
|
||||||
// return <name, contents>[]
|
// return <name, contents>[]
|
||||||
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, std::string const& filename, std::string* ex_dir)
|
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir)
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::string, std::string>> ret;
|
std::vector<std::pair<std::string, std::string>> ret;
|
||||||
|
|
||||||
|
|
@ -68,7 +67,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
||||||
std::vector<std::string> rargs;
|
std::vector<std::string> rargs;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rargs = opts.process(cmd->first_cmd()->args->strargs(1), false, true, false);
|
rargs = opts.process(cmd->first_cmd()->args->strargs(1), {.stop_on_argument=true});
|
||||||
}
|
}
|
||||||
catch(ztd::option_error& e)
|
catch(ztd::option_error& e)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +77,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
||||||
std::string dir;
|
std::string dir;
|
||||||
if(g_cd && !opts['C'])
|
if(g_cd && !opts['C'])
|
||||||
{
|
{
|
||||||
dir=_pre_cd(filename);
|
dir=_pre_cd(ctx.filename);
|
||||||
if(ex_dir!=nullptr)
|
if(ex_dir!=nullptr)
|
||||||
*ex_dir=dir;
|
*ex_dir=dir;
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +105,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string const& filename, std::string* ex_dir)
|
std::pair<std::string, std::string> do_resolve_raw(condlist_t* cmd, parse_context ctx, std::string* ex_dir)
|
||||||
{
|
{
|
||||||
std::pair<std::string, std::string> ret;
|
std::pair<std::string, std::string> ret;
|
||||||
|
|
||||||
|
|
@ -114,7 +113,7 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
||||||
std::vector<std::string> rargs;
|
std::vector<std::string> rargs;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rargs = opts.process(cmd->first_cmd()->args->strargs(1), false, true, false);
|
rargs = opts.process(cmd->first_cmd()->args->strargs(1), {.stop_on_argument=true} );
|
||||||
}
|
}
|
||||||
catch(ztd::option_error& e)
|
catch(ztd::option_error& e)
|
||||||
{
|
{
|
||||||
|
|
@ -124,7 +123,7 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
||||||
std::string dir;
|
std::string dir;
|
||||||
if(g_cd && !opts['C'])
|
if(g_cd && !opts['C'])
|
||||||
{
|
{
|
||||||
dir=_pre_cd(filename);
|
dir=_pre_cd(ctx.filename);
|
||||||
if(ex_dir!=nullptr)
|
if(ex_dir!=nullptr)
|
||||||
*ex_dir=dir;
|
*ex_dir=dir;
|
||||||
}
|
}
|
||||||
|
|
@ -153,23 +152,33 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<condlist*> do_include_parse(condlist* cmd, std::string const& filename)
|
std::vector<condlist_t*> do_include_parse(condlist_t* cmd, parse_context ctx)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist_t*> ret;
|
||||||
|
|
||||||
std::string dir;
|
std::string dir;
|
||||||
auto incs=do_include_raw(cmd, filename, &dir);
|
auto incs=do_include_raw(cmd, ctx, &dir);
|
||||||
|
|
||||||
for(auto it: incs)
|
std::vector<shmain*> shs;
|
||||||
|
shs.resize(incs.size());
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<incs.size(); i++)
|
||||||
|
{
|
||||||
|
parse_context newctx = make_context(ctx, incs[i].second, incs[i].first);
|
||||||
|
auto pp = parse_text(newctx);
|
||||||
|
shmain* sh = pp.first;
|
||||||
|
resolve(sh, pp.second);
|
||||||
|
shs[i] = sh;
|
||||||
|
}
|
||||||
|
for(auto sh: shs)
|
||||||
{
|
{
|
||||||
shmain* sh=parse_text(it.second, it.first);
|
|
||||||
resolve(sh);
|
|
||||||
// get the cls
|
// get the cls
|
||||||
ret.insert(ret.end(), sh->lst->cls.begin(), sh->lst->cls.end());
|
ret.insert(ret.end(), sh->lst->cls.begin(), sh->lst->cls.end());
|
||||||
// safety and cleanup
|
// safety and cleanup
|
||||||
sh->lst->cls.resize(0);
|
sh->lst->cls.resize(0);
|
||||||
delete sh;
|
delete sh;
|
||||||
}
|
}
|
||||||
|
shs.resize(0);
|
||||||
// cd back
|
// cd back
|
||||||
_cd(dir);
|
_cd(dir);
|
||||||
|
|
||||||
|
|
@ -177,19 +186,22 @@ std::vector<condlist*> do_include_parse(condlist* cmd, std::string const& filena
|
||||||
}
|
}
|
||||||
|
|
||||||
// if first is nullptr: is a string
|
// if first is nullptr: is a string
|
||||||
std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filename)
|
std::vector<condlist_t*> do_resolve_parse(condlist_t* cmd, parse_context ctx)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist_t*> ret;
|
||||||
|
|
||||||
std::pair<std::string,std::string> p;
|
std::pair<std::string,std::string> p;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// get
|
// get
|
||||||
std::string dir;
|
std::string dir;
|
||||||
p=do_resolve_raw(cmd, filename, &dir);
|
p=do_resolve_raw(cmd, ctx, &dir);
|
||||||
|
|
||||||
// do parse
|
// do parse
|
||||||
shmain* sh = parse_text(p.second);
|
parse_context newctx = make_context(ctx, p.second, '`'+p.first+'`');
|
||||||
resolve(sh);
|
auto pp = parse_text(newctx);
|
||||||
|
shmain* sh = pp.first;
|
||||||
|
resolve(sh, pp.second);
|
||||||
// get the cls
|
// get the cls
|
||||||
ret = sh->lst->cls;
|
ret = sh->lst->cls;
|
||||||
// safety and cleanup
|
// safety and cleanup
|
||||||
|
|
@ -198,9 +210,9 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
||||||
// cd back
|
// cd back
|
||||||
_cd(dir);
|
_cd(dir);
|
||||||
}
|
}
|
||||||
catch(ztd::format_error& e)
|
catch(format_error& e)
|
||||||
{
|
{
|
||||||
throw ztd::format_error(e.what(), '`'+p.first+'`', e.data(), e.where());
|
throw format_error(e.what(), '`'+p.first+'`', e.data(), e.where());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -208,30 +220,30 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
||||||
|
|
||||||
// -- OBJECT CALLS --
|
// -- OBJECT CALLS --
|
||||||
|
|
||||||
std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, std::string const& filename)
|
std::pair< std::vector<condlist_t*> , bool > resolve_condlist(condlist_t* in, parse_context ctx)
|
||||||
{
|
{
|
||||||
cmd* tc = in->first_cmd();
|
cmd_t* tc = in->first_cmd();
|
||||||
if(tc == nullptr)
|
if(tc == nullptr)
|
||||||
return std::make_pair(std::vector<condlist*>(), false);
|
return std::make_pair(std::vector<condlist_t*>(), false);
|
||||||
|
|
||||||
std::string const& strcmd=tc->arg_string(0);
|
std::string const& strcmd=tc->arg_string(0);
|
||||||
|
|
||||||
if(g_include && strcmd == "%include")
|
if(g_include && strcmd == "%include")
|
||||||
return std::make_pair(do_include_parse(in, filename), true);
|
return std::make_pair(do_include_parse(in, ctx), true);
|
||||||
else if(g_resolve && strcmd == "%resolve")
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
return std::make_pair(do_resolve_parse(in, filename), true);
|
return std::make_pair(do_resolve_parse(in, ctx), true);
|
||||||
else
|
else
|
||||||
return std::make_pair(std::vector<condlist*>(), false);
|
return std::make_pair(std::vector<condlist_t*>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& filename, bool forcequote=false)
|
std::pair< std::vector<arg_t*> , bool > resolve_arg(arg_t* in, parse_context ctx, bool forcequote=false)
|
||||||
{
|
{
|
||||||
std::vector<arg*> ret;
|
std::vector<arg_t*> ret;
|
||||||
if(in == nullptr)
|
if(in == nullptr)
|
||||||
{
|
{
|
||||||
return std::make_pair(ret, false);
|
return std::make_pair(ret, false);
|
||||||
}
|
}
|
||||||
arg* ta=nullptr;
|
arg_t* ta=nullptr;
|
||||||
bool has_resolved=false;
|
bool has_resolved=false;
|
||||||
uint32_t j=0;
|
uint32_t j=0;
|
||||||
for(uint32_t i=0 ; i<in->size() ; i++)
|
for(uint32_t i=0 ; i<in->size() ; i++)
|
||||||
|
|
@ -239,23 +251,23 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
||||||
if(in->sa[i]->type != _obj::subarg_subshell) // skip if not subshell
|
if(in->sa[i]->type != _obj::subarg_subshell) // skip if not subshell
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
subshell_subarg* tsh = dynamic_cast<subshell_subarg*>(in->sa[i]);
|
subarg_subshell_t* tsh = dynamic_cast<subarg_subshell_t*>(in->sa[i]);
|
||||||
if(tsh->sbsh->lst->cls.size() != 1) // skip if not one cl
|
if(tsh->sbsh->lst->cls.size() != 1) // skip if not one cl
|
||||||
continue;
|
continue;
|
||||||
condlist* tc = tsh->sbsh->lst->cls[0];
|
condlist_t* tc = tsh->sbsh->lst->cls[0];
|
||||||
cmd* c = tc->first_cmd();
|
cmd_t* c = tc->first_cmd();
|
||||||
if(c == nullptr) // skip if not cmd
|
if(c == nullptr) // skip if not cmd
|
||||||
continue;
|
continue;
|
||||||
std::string strcmd=c->arg_string(0);
|
std::string strcmd=c->arg_string(0);
|
||||||
std::string fulltext;
|
std::string fulltext;
|
||||||
if(g_include && strcmd == "%include")
|
if(g_include && strcmd == "%include")
|
||||||
{
|
{
|
||||||
for(auto it: do_include_raw(tc, filename) )
|
for(auto it: do_include_raw(tc, ctx) )
|
||||||
fulltext += it.second;
|
fulltext += it.second;
|
||||||
}
|
}
|
||||||
else if(g_resolve && strcmd == "%resolve")
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
{
|
{
|
||||||
fulltext = do_resolve_raw(tc, filename).second;
|
fulltext = do_resolve_raw(tc, ctx).second;
|
||||||
}
|
}
|
||||||
else // skip
|
else // skip
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -265,18 +277,24 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
||||||
|
|
||||||
if(tsh->quoted || forcequote)
|
if(tsh->quoted || forcequote)
|
||||||
{
|
{
|
||||||
stringReplace(fulltext, "\"", "\\\"");
|
fulltext = stringReplace(fulltext, "\\\"", "\\\\\"");
|
||||||
stringReplace(fulltext, "!", "\\!");
|
fulltext = escape_chars(fulltext, "\"`$");
|
||||||
|
fulltext = stringReplace(fulltext, "!", "\"\\!\"");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fulltext = escape_chars(fulltext, "\\\"!$`#&|()';<>");
|
||||||
|
}
|
||||||
|
|
||||||
if(!tsh->quoted && forcequote)
|
if(!tsh->quoted && forcequote)
|
||||||
fulltext = '"' + fulltext + '"';
|
fulltext = '"' + fulltext + '"';
|
||||||
|
|
||||||
|
|
||||||
if(tsh->quoted || forcequote)
|
if(tsh->quoted || forcequote)
|
||||||
{
|
{
|
||||||
// replace with new subarg
|
// replace with new subarg
|
||||||
delete in->sa[i];
|
delete in->sa[i];
|
||||||
in->sa[i] = new string_subarg(fulltext);
|
in->sa[i] = new subarg_string_t(fulltext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -287,21 +305,21 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
||||||
if(strargs.size() == 1)
|
if(strargs.size() == 1)
|
||||||
val = strargs[0];
|
val = strargs[0];
|
||||||
delete in->sa[i];
|
delete in->sa[i];
|
||||||
in->sa[i] = new string_subarg(val);
|
in->sa[i] = new subarg_string_t(val);
|
||||||
}
|
}
|
||||||
else // pack
|
else // pack
|
||||||
{
|
{
|
||||||
if(ta == nullptr)
|
if(ta == nullptr)
|
||||||
ta = new arg;
|
ta = new arg_t;
|
||||||
ta->sa.insert(ta->sa.end(), in->sa.begin()+j, in->sa.begin()+i);
|
ta->sa.insert(ta->sa.end(), in->sa.begin()+j, in->sa.begin()+i);
|
||||||
ta->add(new string_subarg(strargs[i]));
|
ta->add(new subarg_string_t(strargs[i]));
|
||||||
j=i+1;
|
j=i+1;
|
||||||
delete in->sa[i];
|
delete in->sa[i];
|
||||||
for(uint32_t li=1 ; li<strargs.size() ; li++)
|
for(uint32_t li=1 ; li<strargs.size() ; li++)
|
||||||
{
|
{
|
||||||
ret.push_back(ta);
|
ret.push_back(ta);
|
||||||
ta = new arg;
|
ta = new arg_t;
|
||||||
ta->add(new string_subarg(strargs[li]));
|
ta->add(new subarg_string_t(strargs[li]));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end pack
|
} // end pack
|
||||||
|
|
@ -321,10 +339,10 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
||||||
return std::make_pair(ret, has_resolved);
|
return std::make_pair(ret, has_resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resolve(_obj* in, parse_context* ctx);
|
||||||
// -- RECURSIVE CALL --
|
// -- RECURSIVE CALL --
|
||||||
|
|
||||||
bool r_resolve(_obj* o, std::string* filename)
|
bool r_resolve(_obj* o, parse_context* ct)
|
||||||
{
|
{
|
||||||
switch(o->type)
|
switch(o->type)
|
||||||
{
|
{
|
||||||
|
|
@ -332,12 +350,12 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
// check every sub-object
|
// check every sub-object
|
||||||
// execute resolve manually
|
// execute resolve manually
|
||||||
// instruct parent resolve to not resolve
|
// instruct parent resolve to not resolve
|
||||||
case _obj::_list :
|
case _obj::list :
|
||||||
{
|
{
|
||||||
auto t = dynamic_cast<list*>(o);
|
auto t = dynamic_cast<list_t*>(o);
|
||||||
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_condlist(t->cls[i], *filename);
|
auto r=resolve_condlist(t->cls[i], *ct);
|
||||||
if(r.second)
|
if(r.second)
|
||||||
{
|
{
|
||||||
// add new cls after current
|
// add new cls after current
|
||||||
|
|
@ -350,17 +368,17 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->cls[i], filename);
|
resolve(t->cls[i], ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
case _obj::_arglist :
|
case _obj::arglist :
|
||||||
{
|
{
|
||||||
auto t = dynamic_cast<arglist*>(o);
|
auto t = dynamic_cast<arglist_t*>(o);
|
||||||
for(uint32_t i=0 ; i<t->size() ; i++)
|
for(uint32_t i=0 ; i<t->size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_arg(t->args[i], *filename);
|
auto r=resolve_arg(t->args[i], *ct);
|
||||||
if(r.first.size()>0)
|
if(r.first.size()>0)
|
||||||
{
|
{
|
||||||
// add new args
|
// add new args
|
||||||
|
|
@ -372,38 +390,43 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->args[i], filename);
|
resolve(t->args[i], ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
case _obj::block_cmd :
|
case _obj::block_cmd :
|
||||||
{
|
{
|
||||||
auto t = dynamic_cast<cmd*>(o);
|
auto t = dynamic_cast<cmd_t*>(o);
|
||||||
for(auto it: t->var_assigns) // var assigns
|
for(auto it: t->var_assigns) // var assigns
|
||||||
{
|
{
|
||||||
resolve_arg(it.second, *filename, true); // force quoted
|
resolve_arg(it.second, *ct, true); // force quoted
|
||||||
resolve(it.second, filename);
|
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, filename);
|
resolve(it, ct);
|
||||||
resolve(t->args, filename);
|
resolve(t->args, ct);
|
||||||
return false;
|
return false;
|
||||||
}; break;
|
}; break;
|
||||||
case _obj::block_case :
|
case _obj::block_case :
|
||||||
{
|
{
|
||||||
auto t = dynamic_cast<case_block*>(o);
|
auto t = dynamic_cast<case_t*>(o);
|
||||||
for(auto sc: t->cases)
|
for(auto sc: t->cases)
|
||||||
{
|
{
|
||||||
resolve_arg(t->carg, *filename, true); // force quoted
|
resolve_arg(t->carg, *ct, true); // force quoted
|
||||||
resolve(t->carg, filename);
|
resolve(t->carg, ct);
|
||||||
|
|
||||||
for(auto it: sc.first)
|
for(auto it: sc.first)
|
||||||
{
|
{
|
||||||
resolve_arg(it, *filename, true); // force quoted
|
resolve_arg(it, *ct, true); // force quoted
|
||||||
resolve(it, filename);
|
resolve(it, ct);
|
||||||
}
|
}
|
||||||
resolve(sc.second, filename);
|
resolve(sc.second, ct);
|
||||||
}
|
}
|
||||||
}; break;
|
}; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
@ -412,12 +435,13 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive call of resolve
|
// recursive call of resolve
|
||||||
void resolve(_obj* in, std::string* filename)
|
void resolve(_obj* in, parse_context* ctx)
|
||||||
{
|
{
|
||||||
recurse(r_resolve, in, filename);
|
recurse(r_resolve, in, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(shmain* sh)
|
// recursive call of resolve
|
||||||
|
void resolve(_obj* in, parse_context ctx)
|
||||||
{
|
{
|
||||||
recurse(r_resolve, sh, &sh->filename);
|
recurse(r_resolve, in, &ctx);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
#include "processing.hpp"
|
#include "processing.hpp"
|
||||||
#include "struc_helper.hpp"
|
#include "struc_helper.hpp"
|
||||||
|
|
||||||
const std::map<const std::string, const struct lxsh_fct> lxsh_extend_fcts = {
|
const std::map<const std::string, const lxsh_fct> lxsh_extend_fcts = {
|
||||||
{ "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(k*8). Default 2", RANDOM_SH} },
|
{ "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(K*8). Default 2", RANDOM_SH} },
|
||||||
{ "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} },
|
{ "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} },
|
||||||
{ "_lxsh_random_tmpfile", { "[N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} } }
|
{ "_lxsh_random_tmpfile", { "[PREFIX] [N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::map<const std::string, const struct lxsh_fct> lxsh_array_fcts = {
|
const std::map<const std::string, const lxsh_fct> lxsh_array_fcts = {
|
||||||
{ "_lxsh_array_create", { "<VAL...>", "Create an array out of input arguments", ARRAY_CREATE_SH} },
|
{ "_lxsh_array_create", { "<VAL...>", "Create an array out of input arguments", ARRAY_CREATE_SH} },
|
||||||
{ "_lxsh_array_get", { "<ARRAY> <I>", "Get value from array", ARRAY_GET_SH} },
|
{ "_lxsh_array_get", { "<ARRAY> <I>", "Get value from array", ARRAY_GET_SH} },
|
||||||
{ "_lxsh_array_set", { "<ARRAY> <I> <VAL>", "Set value of array", ARRAY_SET_SH} },
|
{ "_lxsh_array_set", { "<ARRAY> <I> <VAL>", "Set value of array", ARRAY_SET_SH} },
|
||||||
|
|
@ -19,7 +20,7 @@ const std::map<const std::string, const struct lxsh_fct> lxsh_array_fcts = {
|
||||||
{ "_lxsh_map_set", { "<MAP> <KEY> <VAL>", "Set value of map", MAP_SET_SH} }
|
{ "_lxsh_map_set", { "<MAP> <KEY> <VAL>", "Set value of map", MAP_SET_SH} }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<const std::string, const struct lxsh_fct> create_allfcts()
|
std::map<const std::string, const lxsh_fct> create_allfcts()
|
||||||
{
|
{
|
||||||
auto r = lxsh_array_fcts;
|
auto r = lxsh_array_fcts;
|
||||||
for(auto it: lxsh_extend_fcts)
|
for(auto it: lxsh_extend_fcts)
|
||||||
|
|
@ -27,7 +28,7 @@ std::map<const std::string, const struct lxsh_fct> create_allfcts()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<const std::string, const struct lxsh_fct> lxsh_allfcts = create_allfcts();
|
const std::map<const std::string, const lxsh_fct> lxsh_allfcts = create_allfcts();
|
||||||
|
|
||||||
void add_lxsh_fcts(shmain* sh, std::set<std::string> fcts)
|
void add_lxsh_fcts(shmain* sh, std::set<std::string> fcts)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,11 @@
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
std::string g_origin="";
|
const std::string cmd_t::empty_string="";
|
||||||
|
|
||||||
const std::string cmd::empty_string="";
|
condlist_t::condlist_t(block_t* bl)
|
||||||
|
|
||||||
condlist::condlist(block* bl)
|
|
||||||
{
|
{
|
||||||
type=_obj::_condlist;
|
type=_obj::condlist;
|
||||||
parallel=false;
|
parallel=false;
|
||||||
this->add(new pipeline(bl));
|
this->add(new pipeline_t(bl));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,107 +7,163 @@
|
||||||
|
|
||||||
// makers
|
// makers
|
||||||
|
|
||||||
arg* make_arg(std::string const& in)
|
arg_t* make_arg(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_arg(in.c_str(), in.size(), 0).first;
|
return parse_arg(make_context(in)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* make_cmd(std::vector<std::string> const& args)
|
cmd_t* make_cmd(std::vector<const char*> const& args)
|
||||||
{
|
{
|
||||||
cmd* ret = new cmd;
|
cmd_t* ret = new cmd_t;
|
||||||
ret->args = new arglist;
|
ret->args = new arglist_t;
|
||||||
for(auto it: args)
|
for(auto it: args)
|
||||||
ret->args->add(new arg(it));
|
ret->args->add(new arg_t(it));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* make_cmd(std::vector<arg*> const& args)
|
cmd_t* make_cmd(std::vector<std::string> const& args)
|
||||||
{
|
{
|
||||||
cmd* ret = new cmd;
|
cmd_t* ret = new cmd_t;
|
||||||
ret->args = new arglist;
|
ret->args = new arglist_t;
|
||||||
|
for(auto it: args)
|
||||||
|
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* make_cmd(std::string const& in)
|
cmd_t* make_cmd(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_cmd(in.c_str(), in.size(), 0).first;
|
return parse_cmd(make_context(in)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline* make_pipeline(std::vector<block*> const& bls)
|
pipeline_t* make_pipeline(std::vector<block_t*> const& bls)
|
||||||
{
|
{
|
||||||
pipeline* ret = new pipeline;
|
pipeline_t* ret = new pipeline_t;
|
||||||
for(auto it: bls)
|
for(auto it: bls)
|
||||||
ret->add(it);
|
ret->add(it);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline* make_pipeline(std::string const& in)
|
pipeline_t* make_pipeline(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_pipeline(in.c_str(), in.size(), 0).first;
|
return parse_pipeline(make_context(in)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
condlist* make_condlist(std::string const& in)
|
condlist_t* make_condlist(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_condlist(in.c_str(), in.size(), 0).first;
|
return parse_condlist(make_context(in)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
list* make_list(std::string const& in)
|
list_t* make_list(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_list_until(in.c_str(), in.size(), 0, 0).first;
|
auto t = parse_list_until(make_context(in));
|
||||||
|
return std::get<0>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
block* make_block(std::string const& in)
|
block_t* make_block(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_block(in.c_str(), in.size(), 0).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* copy(arg* in) {
|
arg_t* copy(arg_t* in) {
|
||||||
std::string str = in->generate(0);
|
std::string str = in->generate(0);
|
||||||
return parse_arg(str.c_str(), str.size(), 0).first;
|
return parse_arg(make_context(str)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// modifiers
|
// modifiers
|
||||||
|
|
||||||
void force_quotes(arg* in)
|
void force_quotes(arg_t* in)
|
||||||
{
|
{
|
||||||
for(uint32_t i=0; i < in->sa.size() ; i++)
|
for(uint32_t i=0; i < in->sa.size() ; i++)
|
||||||
{
|
{
|
||||||
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, new string_subarg("\""));
|
in->insert(i+1, "\"");
|
||||||
in->insert(i, new string_subarg("\""));
|
in->insert(i, "\"");
|
||||||
i+=2;
|
i+=2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_quotes(arg* in)
|
void add_quotes(arg_t* in)
|
||||||
{
|
{
|
||||||
for(uint32_t i=0; i < in->sa.size() ; i++)
|
for(uint32_t i=0; i < in->sa.size() ; i++)
|
||||||
in->sa[i]->quoted=true;
|
in->sa[i]->quoted=true;
|
||||||
|
|
||||||
in->insert(0, new string_subarg("\""));
|
in->insert(0, new subarg_string_t("\""));
|
||||||
in->add(new string_subarg("\""));
|
in->add("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ** TESTERS ** //
|
// ** TESTERS ** //
|
||||||
|
|
||||||
bool arg_has_char(char c, arg* in)
|
bool arg_has_char(char c, arg_t* in)
|
||||||
{
|
{
|
||||||
for(auto it: in->sa)
|
for(auto it: in->sa)
|
||||||
{
|
{
|
||||||
if(it->type == _obj::subarg_string)
|
if(it->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(it);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(it);
|
||||||
if(t->val.find(c) != std::string::npos)
|
if(t->val.find(c) != std::string::npos)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +171,7 @@ bool arg_has_char(char c, arg* in)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool possibly_expands(arg* in)
|
bool possibly_expands(arg_t* in)
|
||||||
{
|
{
|
||||||
for(auto it: in->sa)
|
for(auto it: in->sa)
|
||||||
if( (it->type == _obj::subarg_subshell || it->type == _obj::subarg_variable ) && it->quoted == false)
|
if( (it->type == _obj::subarg_subshell || it->type == _obj::subarg_variable ) && it->quoted == false)
|
||||||
|
|
@ -123,7 +179,7 @@ bool possibly_expands(arg* in)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool possibly_expands(arglist* in)
|
bool possibly_expands(arglist_t* in)
|
||||||
{
|
{
|
||||||
for(auto it: in->args)
|
for(auto it: in->args)
|
||||||
if(possibly_expands(it))
|
if(possibly_expands(it))
|
||||||
|
|
@ -137,7 +193,16 @@ bool possibly_expands(arglist* in)
|
||||||
|
|
||||||
// property getters
|
// property getters
|
||||||
|
|
||||||
size_t cmd::arglist_size()
|
bool cmd_t::has_var_assign()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
@ -147,21 +212,55 @@ size_t cmd::arglist_size()
|
||||||
|
|
||||||
// string getters
|
// string getters
|
||||||
|
|
||||||
std::string arg::string()
|
bool arg_t::is_string()
|
||||||
{
|
{
|
||||||
if(sa.size() != 1 || sa[0]->type != subarg::subarg_string)
|
return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
|
||||||
return "";
|
|
||||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arg::first_sa_string()
|
std::string arg_t::string()
|
||||||
{
|
{
|
||||||
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string)
|
if(!this->is_string())
|
||||||
return "";
|
return "";
|
||||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
return dynamic_cast<subarg_string_t*>(sa[0])->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> arglist::strargs(uint32_t start)
|
std::string arg_t::first_sa_string()
|
||||||
|
{
|
||||||
|
if(sa.size() <=0 || sa[0]->type != _obj::subarg_string)
|
||||||
|
return "";
|
||||||
|
return dynamic_cast<subarg_string_t*>(sa[0])->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string arglist_t::first_arg_string()
|
||||||
|
{
|
||||||
|
if(args.size()<=0 || args[0] == nullptr)
|
||||||
|
return "";
|
||||||
|
return args[0]->string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arg_t::can_expand()
|
||||||
|
{
|
||||||
|
for(auto it: sa)
|
||||||
|
{
|
||||||
|
if(it->type != _obj::subarg_string && !it->quoted)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arglist_t::can_expand()
|
||||||
|
{
|
||||||
|
bool arg_expands=false;
|
||||||
|
for(auto it: args)
|
||||||
|
{
|
||||||
|
arg_expands = it->can_expand();
|
||||||
|
if(arg_expands)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> arglist_t::strargs(uint32_t start)
|
||||||
{
|
{
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
bool t=opt_minify;
|
bool t=opt_minify;
|
||||||
|
|
@ -174,16 +273,16 @@ std::vector<std::string> arglist::strargs(uint32_t start)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& cmd::arg_string(uint32_t n)
|
std::string const& cmd_t::arg_string(uint32_t n)
|
||||||
{
|
{
|
||||||
if(args!=nullptr && args->args.size()>n && args->args[n]->sa.size() == 1 && args->args[n]->sa[0]->type == _obj::subarg_string)
|
if(args!=nullptr && args->args.size()>n && args->args[n]->sa.size() == 1 && args->args[n]->sa[0]->type == _obj::subarg_string)
|
||||||
return dynamic_cast<string_subarg*>(args->args[n]->sa[0])->val;
|
return dynamic_cast<subarg_string_t*>(args->args[n]->sa[0])->val;
|
||||||
return cmd::empty_string;
|
return cmd_t::empty_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// subobject getters
|
// subobject getters
|
||||||
|
|
||||||
block* condlist::first_block()
|
block_t* condlist_t::first_block()
|
||||||
{
|
{
|
||||||
if(pls.size() > 0 && pls[0]->cmds.size() > 0)
|
if(pls.size() > 0 && pls[0]->cmds.size() > 0)
|
||||||
return (pls[0]->cmds[0]);
|
return (pls[0]->cmds[0]);
|
||||||
|
|
@ -191,40 +290,40 @@ block* condlist::first_block()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* condlist::first_cmd()
|
cmd_t* condlist_t::first_cmd()
|
||||||
{
|
{
|
||||||
if(pls.size() > 0 && pls[0]->cmds.size() > 0 && pls[0]->cmds[0]->type == _obj::block_cmd)
|
if(pls.size() > 0 && pls[0]->cmds.size() > 0 && pls[0]->cmds[0]->type == _obj::block_cmd)
|
||||||
return dynamic_cast<cmd*>(pls[0]->cmds[0]);
|
return dynamic_cast<cmd_t*>(pls[0]->cmds[0]);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* brace::single_cmd()
|
cmd_t* brace_t::single_cmd()
|
||||||
{
|
{
|
||||||
if( lst->cls.size() == 1 && // only one condlist
|
if( lst->cls.size() == 1 && // only one condlist
|
||||||
lst->cls[0]->pls.size() == 1 && // only one pipeline
|
lst->cls[0]->pls.size() == 1 && // only one pipeline
|
||||||
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
||||||
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
|
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
|
||||||
return dynamic_cast<cmd*>(lst->cls[0]->pls[0]->cmds[0]); // return command
|
return dynamic_cast<cmd_t*>(lst->cls[0]->pls[0]->cmds[0]); // return command
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* subshell::single_cmd()
|
cmd_t* subshell_t::single_cmd()
|
||||||
{
|
{
|
||||||
if( lst->cls.size() == 1 && // only one condlist
|
if( lst->cls.size() == 1 && // only one condlist
|
||||||
lst->cls[0]->pls.size() == 1 && // only one pipeline
|
lst->cls[0]->pls.size() == 1 && // only one pipeline
|
||||||
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
lst->cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
||||||
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
|
lst->cls[0]->pls[0]->cmds[0]->type == _obj::block_cmd) // block is a command
|
||||||
return dynamic_cast<cmd*>(lst->cls[0]->pls[0]->cmds[0]); // return command
|
return dynamic_cast<cmd_t*>(lst->cls[0]->pls[0]->cmds[0]); // return command
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd* block::single_cmd()
|
cmd_t* block_t::single_cmd()
|
||||||
{
|
{
|
||||||
if(this->type == _obj::block_subshell)
|
if(this->type == _obj::block_subshell)
|
||||||
return dynamic_cast<subshell*>(this)->single_cmd();
|
return dynamic_cast<subshell_t*>(this)->single_cmd();
|
||||||
if(this->type == _obj::block_brace)
|
if(this->type == _obj::block_brace)
|
||||||
return dynamic_cast<brace*>(this)->single_cmd();
|
return dynamic_cast<brace_t*>(this)->single_cmd();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,15 +331,15 @@ cmd* block::single_cmd()
|
||||||
|
|
||||||
// simple setters
|
// simple setters
|
||||||
|
|
||||||
void arg::set(std::string const& str)
|
void arg_t::set(std::string const& str)
|
||||||
{
|
{
|
||||||
for(auto it: sa)
|
for(auto it: sa)
|
||||||
delete it;
|
delete it;
|
||||||
sa.resize(0);
|
sa.resize(0);
|
||||||
sa.push_back(new string_subarg(str));
|
sa.push_back(new subarg_string_t(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
void condlist::prune_first_cmd()
|
void condlist_t::prune_first_cmd()
|
||||||
{
|
{
|
||||||
if(pls.size()>0 && pls[0]->cmds.size()>0)
|
if(pls.size()>0 && pls[0]->cmds.size()>0)
|
||||||
{
|
{
|
||||||
|
|
@ -251,40 +350,42 @@ void condlist::prune_first_cmd()
|
||||||
|
|
||||||
// add/extend
|
// add/extend
|
||||||
|
|
||||||
void arg::insert(uint32_t i, std::string const& in)
|
void arg_t::insert(uint32_t i, std::string const& in)
|
||||||
{
|
{
|
||||||
if(i>0 && sa[i-1]->type == _obj::subarg_string)
|
if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i-1]);
|
||||||
t->val += in;
|
t->val += in;
|
||||||
}
|
}
|
||||||
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i]);
|
||||||
t->val = in + t->val;
|
t->val = in + t->val;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sa.insert(sa.begin()+i, new string_subarg(in));
|
sa.insert(sa.begin()+i, new subarg_string_t(in));
|
||||||
}
|
}
|
||||||
void arg::add(std::string const& in)
|
void arg_t::add(std::string const& in)
|
||||||
{
|
{
|
||||||
this->insert(this->size(), in);
|
this->insert(this->size(), in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void arg::insert(uint32_t i, subarg* val)
|
void arg_t::insert(uint32_t i, subarg_t* val)
|
||||||
{
|
{
|
||||||
if(val->type == _obj::subarg_string)
|
if(val->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* tval = dynamic_cast<string_subarg*>(val);
|
subarg_string_t* tval = dynamic_cast<subarg_string_t*>(val);
|
||||||
if(i>0 && sa[i-1]->type == _obj::subarg_string)
|
if(i>0 && i<=sa.size() && sa[i-1]->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i-1]);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i-1]);
|
||||||
t->val += tval->val;
|
t->val += tval->val;
|
||||||
|
delete val;
|
||||||
}
|
}
|
||||||
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
else if(i<sa.size() && sa[i]->type == _obj::subarg_string)
|
||||||
{
|
{
|
||||||
string_subarg* t = dynamic_cast<string_subarg*>(sa[i]);
|
subarg_string_t* t = dynamic_cast<subarg_string_t*>(sa[i]);
|
||||||
t->val = tval->val + t->val;
|
t->val = tval->val + t->val;
|
||||||
|
delete val;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sa.insert(sa.begin()+i, val);
|
sa.insert(sa.begin()+i, val);
|
||||||
|
|
@ -292,43 +393,43 @@ void arg::insert(uint32_t i, subarg* val)
|
||||||
else
|
else
|
||||||
sa.insert(sa.begin()+i, val);
|
sa.insert(sa.begin()+i, val);
|
||||||
}
|
}
|
||||||
void arg::insert(uint32_t i, arg const& a)
|
void arg_t::insert(uint32_t i, arg_t const& a)
|
||||||
{
|
{
|
||||||
sa.insert(sa.begin()+i, a.sa.begin(), a.sa.end());
|
sa.insert(sa.begin()+i, a.sa.begin(), a.sa.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void arglist::insert(uint32_t i, arg* val)
|
void arglist_t::insert(uint32_t i, arg_t* val)
|
||||||
{
|
{
|
||||||
args.insert(args.begin()+i, val);
|
args.insert(args.begin()+i, val);
|
||||||
}
|
}
|
||||||
void arglist::insert(uint32_t i, arglist const& lst)
|
void arglist_t::insert(uint32_t i, arglist_t const& lst)
|
||||||
{
|
{
|
||||||
args.insert(args.begin()+i, lst.args.begin(), lst.args.end());
|
args.insert(args.begin()+i, lst.args.begin(), lst.args.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd::add(arg* in)
|
void cmd_t::add(arg_t* in)
|
||||||
{
|
{
|
||||||
if(args==nullptr)
|
if(args==nullptr)
|
||||||
args = new arglist;
|
args = new arglist_t;
|
||||||
|
|
||||||
args->add(in);
|
args->add(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void condlist::add(pipeline* pl, bool or_op)
|
void condlist_t::add(pipeline_t* pl, bool or_op)
|
||||||
{
|
{
|
||||||
if(pls.size() > 0)
|
if(pls.size() > 0)
|
||||||
or_ops.push_back(or_op);
|
or_ops.push_back(or_op);
|
||||||
pls.push_back(pl);
|
pls.push_back(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void list::insert(uint32_t i, condlist* val)
|
void list_t::insert(uint32_t i, condlist_t* val)
|
||||||
{
|
{
|
||||||
if(i<0)
|
if(i<0)
|
||||||
cls.insert(cls.end(), val);
|
cls.insert(cls.end(), val);
|
||||||
else
|
else
|
||||||
cls.insert(cls.begin()+i, val);
|
cls.insert(cls.begin()+i, val);
|
||||||
}
|
}
|
||||||
void list::insert(uint32_t i, list const& lst)
|
void list_t::insert(uint32_t i, list_t const& lst)
|
||||||
{
|
{
|
||||||
if(i<0)
|
if(i<0)
|
||||||
cls.insert(cls.end(), lst.cls.begin(), lst.cls.end());
|
cls.insert(cls.end(), lst.cls.begin(), lst.cls.end());
|
||||||
|
|
@ -346,7 +447,7 @@ void shmain::concat(shmain* in)
|
||||||
|
|
||||||
// special modifiers
|
// special modifiers
|
||||||
|
|
||||||
void condlist::negate()
|
void condlist_t::negate()
|
||||||
{
|
{
|
||||||
// invert commands
|
// invert commands
|
||||||
for(uint32_t i=0; i<pls.size(); i++)
|
for(uint32_t i=0; i<pls.size(); i++)
|
||||||
|
|
|
||||||
106
src/util.cpp
106
src/util.cpp
|
|
@ -7,8 +7,10 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <ztd/shell.hpp>
|
#include <ztd/shell.hpp>
|
||||||
|
#include <ztd/color.hpp>
|
||||||
|
|
||||||
std::string indenting_string="\t";
|
std::string indenting_string="\t";
|
||||||
|
|
||||||
|
|
@ -43,14 +45,6 @@ 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;
|
||||||
|
|
@ -202,6 +196,19 @@ 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;
|
||||||
|
|
@ -210,16 +217,15 @@ std::string repeatString(std::string const& str, uint32_t n)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printFormatError(ztd::format_error const& e, bool print_line)
|
void printFormatError(format_error const& e, bool print_line)
|
||||||
{
|
{
|
||||||
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
|
const char* in = e.data();
|
||||||
}
|
|
||||||
|
|
||||||
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line)
|
uint64_t index = e.where();
|
||||||
{
|
|
||||||
int i=0, j=0; // j: last newline
|
uint64_t i=0, j=0; // j: last newline
|
||||||
int line=1; //n: line #
|
uint64_t line=1; //n: line #
|
||||||
int in_size=strlen(in);
|
uint64_t in_size=strlen(in);
|
||||||
if(index >= 0)
|
if(index >= 0)
|
||||||
{
|
{
|
||||||
while(i < in_size && i < index)
|
while(i < in_size && i < index)
|
||||||
|
|
@ -232,59 +238,25 @@ void printErrorIndex(const char* in, const int index, const std::string& message
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
while(i < in_size && in[i]!='\n')
|
while(i < in_size && in[i]!='\n')
|
||||||
{
|
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(origin != "")
|
std::cerr << ztd::color::b_white;
|
||||||
|
fprintf(stderr, "%s:%lu:%lu: ", e.origin(), line, index-j+1);
|
||||||
|
|
||||||
|
ztd::color level_color;
|
||||||
|
const std::string& level = e.level();
|
||||||
|
if(level == "error")
|
||||||
|
level_color = ztd::color::b_red;
|
||||||
|
else if(level == "warning")
|
||||||
|
level_color = ztd::color::b_magenta;
|
||||||
|
else if(level == "info")
|
||||||
|
level_color = ztd::color::b_cyan;
|
||||||
|
|
||||||
|
std::cerr << level_color << e.level() << ztd::color::none;
|
||||||
|
fprintf(stderr, ": %s\n", e.what());
|
||||||
|
if(print_line)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s:%u:%u: %s\n", origin.c_str(), line, index-j+1, message.c_str());
|
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||||
if(print_line)
|
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||||
{
|
|
||||||
std::cerr << std::string(in+j, i-j) << std::endl;
|
|
||||||
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int execute(shmain* sh, std::vector<std::string>& args)
|
|
||||||
{
|
|
||||||
std::string data=sh->generate();
|
|
||||||
|
|
||||||
std::string filename = basename(args[0]);
|
|
||||||
|
|
||||||
// generate path
|
|
||||||
std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ;
|
|
||||||
std::string dirpath = tmpdir + "/lxsh_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10");
|
|
||||||
std::string filepath = dirpath+'/'+filename;
|
|
||||||
|
|
||||||
// create dir
|
|
||||||
if(ztd::exec("mkdir", "-p", dirpath).second)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Failed to create directory '"+dirpath+'\'');
|
|
||||||
}
|
|
||||||
|
|
||||||
// create stream
|
|
||||||
std::ofstream stream(filepath);
|
|
||||||
if(!stream)
|
|
||||||
{
|
|
||||||
ztd::exec("rm", "-rf", dirpath);
|
|
||||||
throw std::runtime_error("Failed to write to '"+filepath+'\'');
|
|
||||||
}
|
|
||||||
|
|
||||||
// output
|
|
||||||
stream << data;
|
|
||||||
stream.close();
|
|
||||||
if(ztd::exec("chmod", "+x", filepath).second != 0)
|
|
||||||
{
|
|
||||||
ztd::exec("rm", "-rf", dirpath);
|
|
||||||
throw std::runtime_error("Failed to make '"+filepath+"' executable");
|
|
||||||
}
|
|
||||||
|
|
||||||
// exec
|
|
||||||
int retval=_exec(filepath, args);
|
|
||||||
ztd::exec("rm", "-rf", dirpath);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
47
test/a.bash
Normal file
47
test/a.bash
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
diff <(echo a) <(echo b)
|
||||||
|
|
||||||
|
write_to_file() { echo "$2" > "$1"; }
|
||||||
|
write_to_file >(grep bar) bar
|
||||||
|
wait $!
|
||||||
|
|
||||||
|
echo a &> /tmp/foo
|
||||||
|
echo b >& /tmp/bar
|
||||||
|
echo c &>> /tmp/foo
|
||||||
|
|
||||||
|
cat /tmp/bar /tmp/foo
|
||||||
|
rm /tmp/bar /tmp/foo
|
||||||
|
|
||||||
|
|
||||||
|
TOTO="foo
|
||||||
|
bar"
|
||||||
|
grep ar <<< ar$TOTO
|
||||||
|
|
||||||
|
declare -a A
|
||||||
|
A=("fo o" bar)
|
||||||
|
echo ${A[1]}
|
||||||
|
|
||||||
|
declare -A B
|
||||||
|
B[foo]=ta
|
||||||
|
B[bar]=tu
|
||||||
|
echo ${B[foo]}
|
||||||
|
echo ${B[bar]}
|
||||||
|
echo ${B[*]}
|
||||||
|
|
||||||
|
C=([foo]=bar [bar]=foo)
|
||||||
|
echo ${C[foo]}
|
||||||
|
echo ${C[bar]}
|
||||||
|
echo ${C[*]}
|
||||||
|
|
||||||
|
BAR=FOO
|
||||||
|
echo ${!BAR}
|
||||||
|
|
||||||
|
[[ $DEBUG == true ]] && echo debug
|
||||||
|
|
||||||
|
a=a
|
||||||
|
[[ $a = a && foo = fo* && bar =~ b.r || 2 < 3 ]]
|
||||||
|
|
||||||
|
for I in A B C ; do
|
||||||
|
echo "$I"
|
||||||
|
done > >(cat)
|
||||||
4
test/arithmetic.sh
Normal file
4
test/arithmetic.sh
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo $(( (2+1)*3 ))
|
||||||
|
echo $(( $((2+1))*3 ))
|
||||||
38
test/array.bash
Normal file
38
test/array.bash
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TOTO=(toto tata)
|
||||||
|
TOTO[0]=titi
|
||||||
|
TOTO[1]+=tu
|
||||||
|
echo ${TOTO[0]}
|
||||||
|
echo ${TOTO[1]}
|
||||||
|
echo ${TOTO[*]}
|
||||||
|
|
||||||
|
TOTO+=(2)
|
||||||
|
echo $((TOTO[2]+1))
|
||||||
|
echo $((${TOTO[2]}+2))
|
||||||
|
|
||||||
|
declare -a TUTU
|
||||||
|
TUTU=(titi "tu tu")
|
||||||
|
echo ${TUTU[0]}
|
||||||
|
echo ${TUTU[1]}
|
||||||
|
echo ${TUTU[*]}
|
||||||
|
echo "${TUTU[*]}"
|
||||||
|
|
||||||
|
declare -A A
|
||||||
|
A[to]=ta
|
||||||
|
A[ti]=tu
|
||||||
|
echo ${A[to]}
|
||||||
|
echo ${A[ti]}
|
||||||
|
echo ${A[*]}
|
||||||
|
|
||||||
|
declare -A B
|
||||||
|
B=([to]=ta [ti]=tu)
|
||||||
|
echo ${B[to]}
|
||||||
|
echo ${B[ti]}
|
||||||
|
echo ${B[*]}
|
||||||
|
echo "${B[*]}"
|
||||||
|
|
||||||
|
toto=tata
|
||||||
|
C=()
|
||||||
|
C+=($toto)
|
||||||
|
echo ${C[@]}
|
||||||
7
test/backtick.sh
Normal file
7
test/backtick.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo $(echo toto)
|
||||||
|
echo $(printf %s\\n tata)
|
||||||
|
echo `echo titi`
|
||||||
|
echo `printf '%s\\n' tutu`
|
||||||
|
|
||||||
7
test/brace.sh
Normal file
7
test/brace.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{ echo tata ; echo a; } | sed 's|a|toto|g'
|
||||||
|
|
||||||
|
echo a | { grep a && echo b; }
|
||||||
|
|
||||||
|
{ { echo tata ; } }
|
||||||
8
test/braceexp.bash
Normal file
8
test/braceexp.bash
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
echo tot{a,o,i}
|
||||||
|
echo {1..10}
|
||||||
|
echo {0..10..2}
|
||||||
|
echo {1..10..2}
|
||||||
|
echo tot{a,o,i}{1..3}tata
|
||||||
|
echo :{{a..z},{A..Z}}
|
||||||
17
test/case.sh
Normal file
17
test/case.sh
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
echo "$*" | case $1 in
|
||||||
|
to*) echo toto ;;
|
||||||
|
tata) echo wew tata ;;
|
||||||
|
a | b)
|
||||||
|
echo titi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cat ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case foo in bar)echo a;;foo)echo b;esac
|
||||||
|
case foo in bar)echo a;;foo)echo b
|
||||||
|
esac
|
||||||
|
|
||||||
|
case far in foo) echo a;;bar)
|
||||||
|
esac
|
||||||
5
test/comment.sh
Normal file
5
test/comment.sh
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo toto#
|
||||||
|
echo toto#tata
|
||||||
|
echo toto #tata
|
||||||
22
test/complex.sh
Normal file
22
test/complex.sh
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
while [ -z "$I" ]
|
||||||
|
do
|
||||||
|
case $U in
|
||||||
|
*)echo toto;I=y
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo "$I"
|
||||||
|
|
||||||
|
case toto in
|
||||||
|
tutu) ;;
|
||||||
|
|
||||||
|
toto)
|
||||||
|
cat << EOF
|
||||||
|
toto
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
tata)
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo to 2>&1
|
||||||
|
echo to2 >&1
|
||||||
|
echo to$(echo 2) >&1
|
||||||
50
test/debashify.bash
Normal file
50
test/debashify.bash
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
readonly tutu titi=tata
|
||||||
|
echo "$tutu $titi"
|
||||||
|
|
||||||
|
diff <(echo a) <(echo b)
|
||||||
|
|
||||||
|
write_to_file() { echo "$2" > "$1"; }
|
||||||
|
write_to_file >(grep tutu) tutu
|
||||||
|
wait $!
|
||||||
|
|
||||||
|
echo a &> /tmp/toto
|
||||||
|
echo b >& /tmp/tata
|
||||||
|
echo c &>> /tmp/toto
|
||||||
|
|
||||||
|
cat /tmp/tata /tmp/toto
|
||||||
|
rm /tmp/tata /tmp/toto
|
||||||
|
|
||||||
|
|
||||||
|
TOTO="ta
|
||||||
|
to"
|
||||||
|
grep ta <<< toto$TOTO
|
||||||
|
|
||||||
|
TATA=ti
|
||||||
|
TATA+=tu
|
||||||
|
echo $TATA
|
||||||
|
|
||||||
|
[[ $DEBUG == true ]] && echo debug
|
||||||
|
|
||||||
|
[ $((RANDOM+RANDOM)) -gt 0 ]
|
||||||
|
echo randomstat: $?
|
||||||
|
|
||||||
|
a=a
|
||||||
|
[[ $a = a && foo = fo* && bar =~ b.r || 2 < 3 ]]
|
||||||
|
echo $?
|
||||||
|
|
||||||
|
N=1
|
||||||
|
TOTO=tatitu
|
||||||
|
echo "${TOTO:2}"
|
||||||
|
echo "${TOTO:$N:2}"
|
||||||
|
|
||||||
|
echo ${TOTO:-tutu}
|
||||||
|
echo ${TITI:-bar}
|
||||||
|
|
||||||
|
TATA=TOTO
|
||||||
|
echo ${!TATA}
|
||||||
|
|
||||||
|
for I in A B C ; do
|
||||||
|
echo "$I"
|
||||||
|
done 2>&1 > >(grep A)
|
||||||
78
test/dequote.sh
Normal file
78
test/dequote.sh
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
|
||||||
|
toto=tutu
|
||||||
|
tata=titi
|
||||||
|
|
||||||
|
echo "toto tata titi"
|
||||||
|
echo "toto"
|
||||||
|
|
||||||
|
echo "tata"titi
|
||||||
|
|
||||||
|
echo "ta ta"
|
||||||
|
|
||||||
|
echo "$toto"tata
|
||||||
|
|
||||||
|
echo "$toto"
|
||||||
|
|
||||||
|
echo $toto"tata"
|
||||||
|
|
||||||
|
echo $"toto"
|
||||||
|
|
||||||
|
toto="$toto"
|
||||||
|
|
||||||
|
toto="$toto"tata
|
||||||
|
echo "$toto"
|
||||||
|
toto="tata"$tata
|
||||||
|
echo "$toto"
|
||||||
|
toto=$toto"tata"
|
||||||
|
echo "$toto"
|
||||||
|
toto="$toto".tata
|
||||||
|
echo "$toto"
|
||||||
|
|
||||||
|
tata="ta ta"
|
||||||
|
echo "$tata"
|
||||||
|
|
||||||
|
echo "$"
|
||||||
|
echo \$
|
||||||
|
|
||||||
|
toto=tutu
|
||||||
|
tata=titi
|
||||||
|
|
||||||
|
echo 'toto tata titi'
|
||||||
|
echo 'toto'
|
||||||
|
|
||||||
|
echo 'tata'titi
|
||||||
|
|
||||||
|
echo 'ta ta'
|
||||||
|
|
||||||
|
echo '$toto'tata
|
||||||
|
|
||||||
|
echo '$toto'
|
||||||
|
|
||||||
|
echo $toto'tata'
|
||||||
|
|
||||||
|
echo $'toto'
|
||||||
|
|
||||||
|
toto='$toto'
|
||||||
|
|
||||||
|
toto='$toto'tata
|
||||||
|
echo '$toto'
|
||||||
|
toto='tata'$tata
|
||||||
|
echo '$toto'
|
||||||
|
toto=$toto'tata'
|
||||||
|
echo '$toto'
|
||||||
|
toto='$toto'.tata
|
||||||
|
echo '$toto'
|
||||||
|
|
||||||
|
tata='ta ta'
|
||||||
|
echo '$tata'
|
||||||
|
|
||||||
|
echo '$'
|
||||||
|
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
"toto"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "%s\n" "" ""'' "toto"
|
||||||
12
test/echo.bash
Normal file
12
test/echo.bash
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo -n titi:
|
||||||
|
echo -e 'tata\n'
|
||||||
|
echo -E 'tutu\n'
|
||||||
|
|
||||||
|
echo -n tata tutu tete
|
||||||
|
|
||||||
|
toto="to to"
|
||||||
|
echo $toto
|
||||||
|
|
||||||
|
echo to $toto
|
||||||
1
test/err/brace.sh
Normal file
1
test/err/brace.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{ ; }
|
||||||
12
test/err/err.bash
Normal file
12
test/err/err.bash
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
var[a
|
||||||
|
read var+=a
|
||||||
|
export var+=a
|
||||||
|
export var=()
|
||||||
|
|
||||||
|
[[ a = b ]] toto
|
||||||
|
|
||||||
|
echo >() <()
|
||||||
|
|
||||||
|
function toto-titi{ true; }
|
||||||
66
test/err/err.sh
Normal file
66
test/err/err.sh
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
read var=a
|
||||||
|
var+=a
|
||||||
|
var=(foo)
|
||||||
|
|
||||||
|
$((var~2))
|
||||||
|
|
||||||
|
${!var}
|
||||||
|
${~}
|
||||||
|
${#var-a}
|
||||||
|
`echo \`echo\` `
|
||||||
|
|
||||||
|
$(( (var) )
|
||||||
|
|
||||||
|
>& /dev/null
|
||||||
|
echo &> /dev/null
|
||||||
|
|
||||||
|
cat 2< file
|
||||||
|
cat <<< var
|
||||||
|
echo >
|
||||||
|
|
||||||
|
echo &| cat
|
||||||
|
echo |& cat
|
||||||
|
|
||||||
|
[[ a = b ]] foo
|
||||||
|
|
||||||
|
()
|
||||||
|
|
||||||
|
fct() abc
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
fct() { }
|
||||||
|
|
||||||
|
typeset var
|
||||||
|
var=val read var
|
||||||
|
case foo ; esac
|
||||||
|
case foo in aiae ; esac
|
||||||
|
case foo in ) ; esac
|
||||||
|
case foo in a) ; b) esac
|
||||||
|
|
||||||
|
for 2 in a ; do true ; done
|
||||||
|
for foo do ; do true ; done
|
||||||
|
for foo & ; do true ; done
|
||||||
|
for I in ; true ; done
|
||||||
|
|
||||||
|
while
|
||||||
|
do true ; done
|
||||||
|
|
||||||
|
while true ; do
|
||||||
|
done
|
||||||
|
|
||||||
|
if true ;then
|
||||||
|
fi
|
||||||
|
|
||||||
|
if
|
||||||
|
then true ; fi
|
||||||
|
|
||||||
|
if true ; then true ; else
|
||||||
|
fi
|
||||||
|
|
||||||
|
fct-foo() { true; }
|
||||||
|
|
||||||
|
function foo { true; }
|
||||||
|
|
||||||
|
{ foo; } bar
|
||||||
11
test/fct.sh
Normal file
11
test/fct.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
toto() {
|
||||||
|
echo toto
|
||||||
|
}
|
||||||
|
|
||||||
|
tata () {
|
||||||
|
echo tata
|
||||||
|
}
|
||||||
|
|
||||||
|
toto
|
||||||
18
test/for.sh
Normal file
18
test/for.sh
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
__for_fct() {
|
||||||
|
for I in ; do
|
||||||
|
echo $I
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
for N
|
||||||
|
do
|
||||||
|
echo $N
|
||||||
|
done
|
||||||
|
|
||||||
|
for I in $(seq 1 10); do
|
||||||
|
echo "toto $I"
|
||||||
|
done
|
||||||
|
|
||||||
|
__for_fct toto tata
|
||||||
48
test/heredocument.sh
Normal file
48
test/heredocument.sh
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
|
|
||||||
|
toto=toto
|
||||||
|
cat << EOF | grep toto
|
||||||
|
$toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat << EOF |
|
||||||
|
azjeha
|
||||||
|
kijejaze
|
||||||
|
ljksdjk
|
||||||
|
EOF
|
||||||
|
cut -c1
|
||||||
|
|
||||||
|
grep -q toto << EOF &&
|
||||||
|
toto
|
||||||
|
EOF
|
||||||
|
echo found toto
|
||||||
|
|
||||||
|
{ cat << EOF | grep toto; }
|
||||||
|
toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
|
|
||||||
|
( cat << EOF | grep toto )
|
||||||
|
toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
|
|
||||||
|
{ cat << EOF | grep toto && echo true; echo eyy; }
|
||||||
|
toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
|
|
||||||
|
( cat << EOF | grep toto && echo true ; echo eyy )
|
||||||
|
toto
|
||||||
|
tata
|
||||||
|
EOF
|
||||||
11
test/if.sh
Normal file
11
test/if.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ -n "$DEBUG" ]
|
||||||
|
then
|
||||||
|
echo "set"
|
||||||
|
elif [ -n "$TOTO" ]
|
||||||
|
then
|
||||||
|
echo "toto lol"
|
||||||
|
else
|
||||||
|
echo "not set"
|
||||||
|
fi
|
||||||
9
test/include.sh
Normal file
9
test/include.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
RAW="$(%include -f pipe.sh brace.sh)"
|
||||||
|
|
||||||
|
echo "$RAW"
|
||||||
|
|
||||||
|
{ %include -f pipe.sh; } | grep -q arch && echo "btw i use arch"
|
||||||
|
|
||||||
|
%include *.sh
|
||||||
15
test/manip.sh
Normal file
15
test/manip.sh
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
var="marijuana"
|
||||||
|
echo ${#var}
|
||||||
|
|
||||||
|
echo ${var-foo}
|
||||||
|
echo ${var+foo}
|
||||||
|
echo ${foo-foo}
|
||||||
|
echo ${foo+foo}
|
||||||
|
|
||||||
|
echo ${var#*a}
|
||||||
|
echo ${var##*a}
|
||||||
|
echo ${var%a*}
|
||||||
|
echo ${var%%a*}
|
||||||
|
|
||||||
8
test/pipe.sh
Normal file
8
test/pipe.sh
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
grep "^ID=" /etc/os-release | cut -d '=' -f2-
|
||||||
|
|
||||||
|
echo toto | #
|
||||||
|
grep to
|
||||||
|
|
||||||
|
echo '#toto' | grep '#toto'
|
||||||
3
test/prompt.sh
Normal file
3
test/prompt.sh
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
read -r prompt || echo $?
|
||||||
5
test/redir.sh
Normal file
5
test/redir.sh
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ echo toto >&2; } 2>&1
|
||||||
|
|
||||||
|
{ echo tata; }>/dev/null
|
||||||
|
|
||||||
|
grep abc < test/redir.sh
|
||||||
9
test/resolve.sh
Normal file
9
test/resolve.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "a$(%resolve echo tata titi)b"
|
||||||
|
|
||||||
|
echo $(%resolve cut -d ' ' -f1 /proc/uptime)s
|
||||||
|
|
||||||
|
%resolve echo "TIME=$(cut -d ' ' -f1 /proc/uptime)s;echo This was compiled at \${TIME}s uptime"
|
||||||
|
|
||||||
|
FOO=$(%resolve echo bar) echo foo
|
||||||
10
test/subshell.sh
Normal file
10
test/subshell.sh
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
TOTO=toto
|
||||||
|
(TOTO=tata; echo $TOTO; echo a) | sed 's|a|titi|g'
|
||||||
|
echo $TOTO
|
||||||
|
|
||||||
|
echo a | ( grep a && echo b )
|
||||||
|
|
||||||
|
echo ab | ( grep a )
|
||||||
|
pwd
|
||||||
|
(cd /)
|
||||||
|
pwd
|
||||||
31
test/var.sh
Normal file
31
test/var.sh
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
foo()
|
||||||
|
{
|
||||||
|
echo $FOO
|
||||||
|
}
|
||||||
|
|
||||||
|
TOTO=tata
|
||||||
|
TATA=titi
|
||||||
|
echo $TOTO
|
||||||
|
echo "$TOTO $TATA$TITI"
|
||||||
|
echo "${AYE-aye}"
|
||||||
|
|
||||||
|
export TUTU=ta
|
||||||
|
|
||||||
|
foo
|
||||||
|
FOO=bar foo
|
||||||
|
BAR=foo foo
|
||||||
|
ABCD=$(FOO=true foo)
|
||||||
|
echo $ABCD
|
||||||
|
nul=/dev/null
|
||||||
|
echo toto > "$nul"
|
||||||
|
|
||||||
|
somevar=val
|
||||||
|
echo $somevar
|
||||||
|
unset somevar
|
||||||
|
echo $somevar
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
$TOTO
|
||||||
|
EOF
|
||||||
23
test/while.sh
Normal file
23
test/while.sh
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
I=0
|
||||||
|
while [ $I -lt 10 ]
|
||||||
|
do
|
||||||
|
I=$((I+1))
|
||||||
|
echo "$I"
|
||||||
|
done
|
||||||
|
|
||||||
|
I=0
|
||||||
|
until [ $I -eq 10 ]
|
||||||
|
do
|
||||||
|
I=$((I+1))
|
||||||
|
echo "$I"
|
||||||
|
done
|
||||||
|
|
||||||
|
I=0
|
||||||
|
while
|
||||||
|
I=$((I+1))
|
||||||
|
echo "$I"
|
||||||
|
[ $I -lt 10 ]
|
||||||
|
do true
|
||||||
|
done
|
||||||
Loading…
Reference in a new issue