commit
3429a398cf
24 changed files with 1919 additions and 1564 deletions
49
Makefile
49
Makefile
|
|
@ -14,20 +14,16 @@ 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
|
endif
|
||||||
|
|
||||||
ifneq ($(RELEASE), true)
|
|
||||||
VSUFFIX=-dev-$(SHA_SHORT)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(STATIC),true)
|
ifeq ($(STATIC),true)
|
||||||
# static links
|
# static links
|
||||||
LDFLAGS += -l:libztd.a
|
LDFLAGS += -l:libztd.a
|
||||||
|
|
@ -36,43 +32,58 @@ else
|
||||||
LDFLAGS += -lztd
|
LDFLAGS += -lztd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifeq ($(PROFILE),true)
|
||||||
|
CXXFLAGS += -pg
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(RELEASE), true)
|
||||||
|
VSUFFIX=-dev-$(SHA_SHORT)
|
||||||
|
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)
|
||||||
|
|
|
||||||
23
README.md
23
README.md
|
|
@ -8,7 +8,7 @@ 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
|
||||||
|
|
@ -20,7 +20,7 @@ Download the `lxsh.tar.gz` archive, extract it,
|
||||||
and move the `lxsh` binary in a PATH folder (`/usr/local/bin` is the recommended).
|
and move the `lxsh` binary in a PATH folder (`/usr/local/bin` is the recommended).
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
wget https://github.com/zawwz/lxsh/releases/download/v1.1.0/lxsh.tar.gz
|
wget https://github.com/zawwz/lxsh/releases/download/v1.2.0/lxsh-linux-amd64.tar.gz
|
||||||
tar -xvf lxsh.tar.gz
|
tar -xvf lxsh.tar.gz
|
||||||
sudo mv lxsh /usr/local/bin
|
sudo mv lxsh /usr/local/bin
|
||||||
```
|
```
|
||||||
|
|
@ -122,6 +122,23 @@ these features will continue working with undesired behavior.
|
||||||
|
|
||||||
Array argument with `[@]` does not expand into the desired multiple arguments.
|
Array argument with `[@]` does not expand into the desired multiple arguments.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
### Output generated code
|
### Output generated code
|
||||||
|
|
@ -154,7 +171,7 @@ Depends on [ztd](https://github.com/zawwz/ztd)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Use `make -j13` 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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
#include <ztd/filedat.hpp>
|
|
||||||
|
|
||||||
#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;#()&"
|
||||||
|
|
@ -27,59 +27,94 @@
|
||||||
#define ARRAY_ARG_END " \t\n;#()&|<>]"
|
#define ARRAY_ARG_END " \t\n;#()&|<>]"
|
||||||
|
|
||||||
// macros
|
// macros
|
||||||
#define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i)
|
// #define PARSE_ERROR_I(str, ctx, i) format_error(str, ctx.filename, ctx.data, i)
|
||||||
|
// #define PARSE_ERROR(str, ctx) format_error(str, ctx.filename, ctx.data, ctx.i)
|
||||||
|
// #define PARSE_ERROR_I(str, ctx, i) { printFormatError(format_error(str, ctx.filename, ctx.data, i)); ctx.has_errored=true; }
|
||||||
|
// #define PARSE_ERROR(str, ctx) { printFormatError(format_error(str, ctx.filename, ctx.data, ctx.i)); ctx.has_errored=true; }
|
||||||
|
|
||||||
|
// structs
|
||||||
|
|
||||||
|
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 bool g_bash;
|
|
||||||
|
|
||||||
extern const std::vector<std::string> posix_cmdvar;
|
extern const std::vector<std::string> posix_cmdvar;
|
||||||
extern const std::vector<std::string> bash_cmdvar;
|
extern const std::vector<std::string> bash_cmdvar;
|
||||||
|
|
||||||
std::string import_file(std::string const& path);
|
std::string import_file(std::string const& path);
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
// 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::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL);
|
||||||
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
|
// std::pair<list*, parse_context> parse_list_until(parse_context ct, 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);
|
// std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
||||||
|
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
|
||||||
// name
|
// name
|
||||||
std::pair<variable*, uint32_t> parse_var(const char* in, uint32_t size, uint32_t start, bool specialvars=true, bool array=false);
|
std::pair<variable*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
|
||||||
|
|
||||||
// subarg parsers
|
// subarg parsers
|
||||||
std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start);
|
std::pair<arithmetic*, 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*, 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*, parse_context> parse_arg(parse_context ct, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true);
|
||||||
// redirect parser
|
// redirect parser
|
||||||
std::pair<redirect*, uint32_t> parse_redirect(const char* in, uint32_t size, uint32_t start);
|
std::pair<redirect*, 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*, parse_context> parse_arglist(parse_context ct, bool hard_error=false, std::vector<redirect*>* redirs=nullptr);
|
||||||
// block parsers
|
// block parsers
|
||||||
std::pair<block*, uint32_t> parse_block(const char* in, uint32_t size, uint32_t start);
|
std::pair<block*, 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*, 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*, 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*, 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*, 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_block*, 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_block*, 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_block*, 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_block*, 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*, 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*, parse_context> parse_condlist(parse_context ct);
|
||||||
|
|
||||||
#endif //PARSE_HPP
|
#endif //PARSE_HPP
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,6 @@ bool r_delete_var(_obj* in, set_t* vars);
|
||||||
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);
|
||||||
|
|
||||||
|
void string_processors(_obj* in);
|
||||||
|
|
||||||
#endif //PROCESSING_HPP
|
#endif //PROCESSING_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* 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* 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,6 +62,8 @@ subarg: can be one of
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// pre-definitions
|
||||||
|
|
||||||
#define AND_OP false
|
#define AND_OP false
|
||||||
#define OR_OP true
|
#define OR_OP true
|
||||||
|
|
||||||
|
|
@ -71,6 +73,56 @@ class pipeline;
|
||||||
class arg;
|
class arg;
|
||||||
class subarg;
|
class subarg;
|
||||||
class cmd;
|
class cmd;
|
||||||
|
class redirect;
|
||||||
|
|
||||||
|
// structs
|
||||||
|
|
||||||
|
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* here_document=nullptr;
|
||||||
|
char* here_delimitor=NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct generate_context {
|
||||||
|
arg* 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
|
||||||
|
|
||||||
// type pack of condlist
|
// type pack of condlist
|
||||||
typedef std::vector<arg*> arglist_t;
|
typedef std::vector<arg*> arglist_t;
|
||||||
|
|
@ -135,11 +187,15 @@ public:
|
||||||
|
|
||||||
std::vector<subarg*> sa;
|
std::vector<subarg*> sa;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
@ -179,6 +235,9 @@ public:
|
||||||
|
|
||||||
std::vector<std::string> strargs(uint32_t start);
|
std::vector<std::string> strargs(uint32_t start);
|
||||||
|
|
||||||
|
// potentially expands into more arguments than its size
|
||||||
|
bool can_expand();
|
||||||
|
|
||||||
void insert(uint32_t i, arg* val);
|
void insert(uint32_t i, arg* val);
|
||||||
void insert(uint32_t i, arglist const& lst);
|
void insert(uint32_t i, arglist const& lst);
|
||||||
|
|
||||||
|
|
@ -190,15 +249,20 @@ public:
|
||||||
class redirect : public _obj
|
class redirect : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; }
|
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; here_document=nullptr; }
|
||||||
redirect(arg* in) { type=_obj::_redirect; target=in; }
|
redirect(arg* in) { type=_obj::_redirect; target=in; here_document=nullptr; }
|
||||||
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; }
|
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; here_document=nullptr; }
|
||||||
~redirect() { if(target != nullptr) delete target; }
|
redirect(std::string strop, arg* in, arg* doc) { type=_obj::_redirect; op=strop; target=in; here_document=doc; }
|
||||||
|
~redirect() {
|
||||||
|
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* target;
|
||||||
|
arg* here_document;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Meta block
|
// Meta block
|
||||||
|
|
@ -213,9 +277,9 @@ public:
|
||||||
// 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* 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
|
||||||
|
|
@ -230,7 +294,8 @@ public:
|
||||||
|
|
||||||
bool negated; // negated return value (! at start)
|
bool negated; // negated return value (! at start)
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -331,7 +396,8 @@ public:
|
||||||
|
|
||||||
arglist* args;
|
arglist* args;
|
||||||
|
|
||||||
std::string generate(int ind);
|
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
|
||||||
|
|
@ -349,7 +415,8 @@ public:
|
||||||
list* lst;
|
list* lst;
|
||||||
|
|
||||||
std::string generate(bool print_shebang=true, int ind=0);
|
std::string generate(bool print_shebang=true, int ind=0);
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class subshell : public block
|
class subshell : public block
|
||||||
|
|
@ -365,7 +432,8 @@ public:
|
||||||
|
|
||||||
list* lst;
|
list* 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 : public block
|
||||||
|
|
@ -380,7 +448,8 @@ public:
|
||||||
|
|
||||||
list* lst;
|
list* 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 : public block
|
||||||
|
|
@ -394,7 +463,8 @@ public:
|
||||||
std::string name;
|
std::string name;
|
||||||
list* lst;
|
list* 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_block : public block
|
||||||
|
|
@ -414,7 +484,8 @@ public:
|
||||||
arg* carg;
|
arg* carg;
|
||||||
std::vector< std::pair<std::vector<arg*>, list*> > cases;
|
std::vector< std::pair<std::vector<arg*>, list*> > 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_block : public block
|
||||||
|
|
@ -434,7 +505,8 @@ public:
|
||||||
|
|
||||||
list* else_lst;
|
list* 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_block : public block
|
||||||
|
|
@ -452,7 +524,8 @@ public:
|
||||||
arglist* iter;
|
arglist* iter;
|
||||||
list* ops;
|
list* ops;
|
||||||
|
|
||||||
std::string generate(int ind);
|
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_block : public block
|
||||||
|
|
@ -469,7 +542,8 @@ public:
|
||||||
list* cond;
|
list* cond;
|
||||||
list* ops;
|
list* 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 //
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -149,9 +147,6 @@ 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);
|
||||||
|
|
||||||
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.2.0"
|
||||||
|
|
||||||
#endif //VERSION_H
|
#endif //VERSION_H
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "debashify.hpp"
|
#include "debashify.hpp"
|
||||||
|
|
||||||
#include "ztd/options.hpp"
|
#include <ztd/options.hpp>
|
||||||
|
|
||||||
#include "processing.hpp"
|
#include "processing.hpp"
|
||||||
#include "recursive.hpp"
|
#include "recursive.hpp"
|
||||||
|
|
@ -144,12 +144,11 @@ std::string get_declare_opt(cmd* in)
|
||||||
|
|
||||||
ztd::option_set gen_echo_opts()
|
ztd::option_set gen_echo_opts()
|
||||||
{
|
{
|
||||||
ztd::option_set ret;
|
ztd::option_set ret( std::vector<ztd::option>({
|
||||||
ret.add(
|
|
||||||
ztd::option('e'),
|
ztd::option('e'),
|
||||||
ztd::option('E'),
|
ztd::option('E'),
|
||||||
ztd::option('n')
|
ztd::option('n')
|
||||||
);
|
}) );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,17 +165,24 @@ bool debashify_echo(pipeline* pl)
|
||||||
ztd::option_set opts=gen_echo_opts();
|
ztd::option_set opts=gen_echo_opts();
|
||||||
std::vector<std::string> args=in->args->strargs(1);
|
std::vector<std::string> args=in->args->strargs(1);
|
||||||
std::vector<std::string> postargs;
|
std::vector<std::string> postargs;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
postargs=opts.process(args, true, true);
|
postargs=opts.process(args, {.ignore_numbers=true, .stop_on_argument=true} );
|
||||||
}
|
}
|
||||||
catch(ztd::option_error& e)
|
catch(ztd::option_error& e)
|
||||||
{
|
{
|
||||||
skip=true;
|
skip=true;
|
||||||
}
|
}
|
||||||
if(skip || postargs.size() == args.size()) // no options processed: skip
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
bool enable_interpretation=false;
|
||||||
|
bool newline=true;
|
||||||
|
bool has_escape_sequence=false;
|
||||||
|
bool has_processed_options=false;
|
||||||
|
|
||||||
|
if(!skip && postargs.size() != args.size())
|
||||||
|
{
|
||||||
|
has_processed_options=true;
|
||||||
// delete the number of args that were processed
|
// delete the number of args that were processed
|
||||||
for(uint32_t i=0; i<args.size()-postargs.size(); i++)
|
for(uint32_t i=0; i<args.size()-postargs.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -184,42 +190,99 @@ bool debashify_echo(pipeline* pl)
|
||||||
in->args->args.erase(in->args->args.begin()+1);
|
in->args->args.erase(in->args->args.begin()+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doprintf=false;
|
if(opts['e'])
|
||||||
bool newline=true;
|
enable_interpretation=true;
|
||||||
if(opts['E'])
|
|
||||||
{
|
|
||||||
doprintf=true;
|
|
||||||
}
|
|
||||||
else if(opts['n'])
|
else if(opts['n'])
|
||||||
{
|
|
||||||
doprintf=true;
|
|
||||||
newline=false;
|
newline=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doprintf)
|
for(auto it=in->args->args.begin()+1; it!=in->args->args.end(); it++)
|
||||||
{
|
{
|
||||||
delete in->args->args[0];
|
if(!(*it)->is_string() || (*it)->string().find('\\') != std::string::npos)
|
||||||
in->args->args[0] = new arg("printf");
|
|
||||||
if(possibly_expands(in->args->args[2]) )
|
|
||||||
{
|
{
|
||||||
in->args->insert(1, new arg("%s\\ "));
|
has_escape_sequence=true;
|
||||||
if(newline) // newline: add a newline command at the end
|
break;
|
||||||
{
|
|
||||||
brace* br = new brace(new list);
|
|
||||||
br->lst->add(new condlist(in));
|
|
||||||
br->lst->add(make_condlist("echo"));
|
|
||||||
pl->cmds[0] = br;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newline && !has_escape_sequence)
|
||||||
|
{
|
||||||
|
// newline and no potential escape: don't replace, keep echo
|
||||||
|
return has_processed_options;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string printfarg="'%s";
|
// replace by printf
|
||||||
for(uint32_t i=2; i<in->args->size(); i++)
|
if(!in->args->can_expand())
|
||||||
printfarg+=" %s";
|
{
|
||||||
|
// no potential expansion: static number of args
|
||||||
|
std::string format_str = "'";
|
||||||
|
for(uint32_t i=1; i<in->args->args.size(); i++)
|
||||||
|
{
|
||||||
|
if(enable_interpretation)
|
||||||
|
format_str += "%b ";
|
||||||
|
else
|
||||||
|
format_str += "%s ";
|
||||||
|
}
|
||||||
|
format_str.pop_back();
|
||||||
if(newline)
|
if(newline)
|
||||||
printfarg+="\\n";
|
format_str += "\\n";
|
||||||
printfarg+="'";
|
format_str += '\'';
|
||||||
in->args->insert(1, new arg(printfarg));
|
|
||||||
|
in->args->insert(1, new arg(format_str));
|
||||||
|
delete in->args->args[0];
|
||||||
|
in->args->args[0] = new arg("printf");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string format_str;
|
||||||
|
if(enable_interpretation)
|
||||||
|
format_str = "%b";
|
||||||
|
else
|
||||||
|
format_str = "%s";
|
||||||
|
|
||||||
|
list* lst=nullptr;
|
||||||
|
|
||||||
|
// more than 1 arg and first arg can't expand: can split into two printf
|
||||||
|
// printf '%s' arg1
|
||||||
|
// printf ' %s' args...
|
||||||
|
if(in->args->args.size()>2 && !in->args->args[1]->can_expand())
|
||||||
|
{
|
||||||
|
// extract arg 1
|
||||||
|
arg* arg1 = in->args->args[1];
|
||||||
|
in->args->args.erase(in->args->args.begin()+1);
|
||||||
|
delete in->args->args[0];
|
||||||
|
in->args->args[0] = new arg("printf");
|
||||||
|
|
||||||
|
lst = new list;
|
||||||
|
lst->add(new condlist(make_cmd({new arg("printf"), new arg(format_str+"\\ "), arg1 })));
|
||||||
|
lst->add(new condlist(in));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// can't reliable replace: keep echo if newline
|
||||||
|
if(newline)
|
||||||
|
return has_processed_options;
|
||||||
|
|
||||||
|
in->args->insert(1, new arg(format_str+"\\ "));
|
||||||
|
delete in->args->args[0];
|
||||||
|
in->args->args[0] = new arg("printf");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newline)
|
||||||
|
{
|
||||||
|
if(lst == nullptr)
|
||||||
|
{
|
||||||
|
lst = new list;
|
||||||
|
lst->add(new condlist(in));
|
||||||
|
}
|
||||||
|
lst->add(make_condlist("echo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lst != nullptr)
|
||||||
|
{
|
||||||
|
pl->cmds[0] = new brace(lst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,7 +536,7 @@ bool debashify_array_set(cmd* in, debashify_params* params)
|
||||||
gen=gen.substr(2);
|
gen=gen.substr(2);
|
||||||
gen.pop_back();
|
gen.pop_back();
|
||||||
// create cmd out of arguments
|
// create cmd out of arguments
|
||||||
arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).first;
|
arglist* args = parse_arglist( make_context(gen) ).first;
|
||||||
cmd* c = new cmd(args);
|
cmd* c = new cmd(args);
|
||||||
// cmd first argument is _lxsh_X_create
|
// cmd first argument is _lxsh_X_create
|
||||||
if(params->arrays[varname])
|
if(params->arrays[varname])
|
||||||
|
|
@ -569,7 +632,7 @@ bool debashify_array_set(cmd* in, debashify_params* params)
|
||||||
gen=gen.substr(3);
|
gen=gen.substr(3);
|
||||||
gen.pop_back();
|
gen.pop_back();
|
||||||
// create cmd out of arguments
|
// create cmd out of arguments
|
||||||
arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).first;
|
arglist* args = parse_arglist( make_context(gen) ).first;
|
||||||
cmd* c = new cmd(args);
|
cmd* c = new cmd(args);
|
||||||
// cmd first argument is _lxsh_array_create
|
// cmd first argument is _lxsh_array_create
|
||||||
if(params->arrays[varname])
|
if(params->arrays[varname])
|
||||||
|
|
|
||||||
85
src/exec.cpp
85
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*> do_include_exec(condlist* cmd, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist*> 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,7 +36,7 @@ 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*> do_resolve_exec(condlist* cmd, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
|
@ -45,15 +45,15 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filenam
|
||||||
{
|
{
|
||||||
// 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,7 +61,7 @@ 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* in, parse_context ctx, FILE* fd)
|
||||||
{
|
{
|
||||||
cmd* tc = in->first_cmd();
|
cmd* tc = in->first_cmd();
|
||||||
if(tc == nullptr)
|
if(tc == nullptr)
|
||||||
|
|
@ -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* 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,26 +138,27 @@ 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
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
debashify_params debash_params;
|
debashify_params debash_params;
|
||||||
list* t_lst=new list;
|
list* t_lst=new list;
|
||||||
if(t_lst == nullptr)
|
if(t_lst == nullptr)
|
||||||
throw std::runtime_error("Alloc error");
|
throw std::runtime_error("Alloc error");
|
||||||
while(i<size)
|
while(ctx.i<ctx.size)
|
||||||
{
|
{
|
||||||
auto pp=parse_condlist(in, size, i);
|
auto pp=parse_condlist(ctx);
|
||||||
i=pp.second;
|
ctx=pp.second;
|
||||||
|
if(ctx.has_errored)
|
||||||
|
{
|
||||||
|
parse_list_until(ctx);
|
||||||
|
throw std::runtime_error("Aborting due to previous errors");
|
||||||
|
}
|
||||||
t_lst->add(pp.first);
|
t_lst->add(pp.first);
|
||||||
if(g_resolve || g_include)
|
if(g_resolve || g_include)
|
||||||
{
|
{
|
||||||
if(resolve_exec(t_lst->cls[0], filename, fd))
|
if(resolve_exec(t_lst->cls[0], ctx, fd))
|
||||||
{
|
{
|
||||||
t_lst->clear();
|
t_lst->clear();
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -172,26 +173,22 @@ void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& file
|
||||||
|
|
||||||
fprintf(fd, "%s", gen.c_str());
|
fprintf(fd, "%s", gen.c_str());
|
||||||
|
|
||||||
if(i < size)
|
if(ctx.i < ctx.size)
|
||||||
{
|
{
|
||||||
if(in[i] == '#')
|
if(ctx[ctx.i] == '#')
|
||||||
; // skip here
|
; // skip here
|
||||||
else if(is_in(in[i], COMMAND_SEPARATOR))
|
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||||
i++; // skip on next char
|
ctx.i++; // skip on next char
|
||||||
else if(is_in(in[i], CONTROL_END))
|
else if(is_in(ctx[ctx.i], CONTROL_END))
|
||||||
throw PARSE_ERROR(strf("Unexpected token: '%c'", in[i]), i);
|
{
|
||||||
|
format_error(strf("Unexpected token: '%c'", ctx[ctx.i]), ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
i = skip_unread(in, size, i);
|
ctx.i = skip_unread(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete t_lst;
|
delete t_lst;
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
}
|
|
||||||
catch(ztd::format_error& e)
|
|
||||||
{
|
|
||||||
throw ztd::format_error(e.what(), filename, in, e.where());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t forkexec(const char* bin, char *const args[])
|
pid_t forkexec(const char* bin, char *const args[])
|
||||||
|
|
@ -205,10 +202,6 @@ pid_t forkexec(const char* bin, char *const args[])
|
||||||
}
|
}
|
||||||
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
|
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 +227,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;
|
||||||
|
|
@ -254,8 +247,6 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
|
||||||
runargs.push_back(NULL);
|
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
|
||||||
{
|
{
|
||||||
|
|
@ -268,7 +259,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ std::string arglist::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pipeline::generate(int ind)
|
std::string pipeline::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -53,11 +53,11 @@ std::string pipeline::generate(int ind)
|
||||||
|
|
||||||
if(negated)
|
if(negated)
|
||||||
ret += "! ";
|
ret += "! ";
|
||||||
ret += cmds[0]->generate(ind);
|
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;
|
||||||
|
|
@ -68,18 +68,27 @@ std::string condlist::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);
|
||||||
}
|
}
|
||||||
if(ret=="")
|
if(ret=="")
|
||||||
return "";
|
return "";
|
||||||
|
if(ctx.here_document != nullptr)
|
||||||
|
{
|
||||||
if(parallel)
|
if(parallel)
|
||||||
|
ret += '&';
|
||||||
|
ret += '\n';
|
||||||
|
ret += ctx.here_document->generate(0);
|
||||||
|
ret += '\n';
|
||||||
|
}
|
||||||
|
else if(parallel)
|
||||||
{
|
{
|
||||||
ret += opt_minify ? "&" : " &\n";
|
ret += opt_minify ? "&" : " &\n";
|
||||||
}
|
}
|
||||||
|
|
@ -123,12 +132,18 @@ std::string redirect::generate(int ind)
|
||||||
|
|
||||||
// BLOCK
|
// BLOCK
|
||||||
|
|
||||||
std::string block::generate_redirs(int ind, std::string const& _str)
|
std::string block::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr)
|
||||||
{
|
{
|
||||||
std::string ret=" ";
|
std::string ret=" ";
|
||||||
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
||||||
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 +154,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_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -169,11 +184,11 @@ 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_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -187,11 +202,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_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -207,11 +222,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::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// open subshell
|
// open subshell
|
||||||
|
|
@ -224,11 +239,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 +256,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::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -253,11 +267,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::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// function definition
|
// function definition
|
||||||
|
|
@ -268,11 +282,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_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += "case " + carg->generate(ind) + " in\n";
|
ret += "case " + carg->generate(ind) + " in\n";
|
||||||
|
|
@ -292,27 +306,30 @@ std::string case_block::generate(int ind)
|
||||||
// end of case: ;;
|
// end of case: ;;
|
||||||
if(opt_minify && ret[ret.size()-1] == '\n') // ;; can be right after command
|
if(opt_minify && ret[ret.size()-1] == '\n') // ;; can be right after command
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += indented(";;\n", ind+1);
|
ret += indented(";;", ind+1);
|
||||||
|
if(!opt_minify)
|
||||||
|
ret+="\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove ;; from last case
|
// replace ;; from last case with ;
|
||||||
if(this->cases.size()>0 && opt_minify)
|
if(this->cases.size()>0 && opt_minify)
|
||||||
{
|
{
|
||||||
ret.erase(ret.size()-3, 2);
|
ret.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// var assigns
|
|
||||||
|
// is a varassign cmd
|
||||||
if(is_cmdvar)
|
if(is_cmdvar)
|
||||||
{
|
{
|
||||||
ret += args->generate(ind) + ' ';
|
ret += args->generate(ind) + ' ';
|
||||||
|
|
@ -328,6 +345,7 @@ std::string cmd::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pre-cmd var assigns
|
||||||
for(auto it: var_assigns)
|
for(auto it: var_assigns)
|
||||||
{
|
{
|
||||||
if(it.first != nullptr)
|
if(it.first != nullptr)
|
||||||
|
|
@ -337,6 +355,7 @@ std::string cmd::generate(int ind)
|
||||||
ret += ' ';
|
ret += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cmd itself
|
||||||
if(args!=nullptr && args->size()>0)
|
if(args!=nullptr && args->size()>0)
|
||||||
{
|
{
|
||||||
// command
|
// command
|
||||||
|
|
@ -351,7 +370,7 @@ std::string cmd::generate(int ind)
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
62
src/main.cpp
62
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,12 +39,7 @@ 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]);
|
oneshot_opt_process(argv[0]);
|
||||||
|
|
||||||
|
|
@ -75,15 +72,16 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
// parsing
|
// parsing
|
||||||
|
|
||||||
shmain* sh = new shmain(new list);
|
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,9 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
first_run=false;
|
first_run=false;
|
||||||
// resolve shebang
|
// resolve shebang
|
||||||
shebang_is_bin = ( basename(argv[0]) == basename(shebang) );
|
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,7 +113,10 @@ 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();
|
||||||
|
|
@ -124,25 +127,27 @@ int main(int argc, char* argv[])
|
||||||
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"])
|
|
||||||
shebang = "#!/bin/sh";
|
|
||||||
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;
|
||||||
|
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);
|
||||||
|
|
@ -166,11 +171,13 @@ int main(int argc, char* argv[])
|
||||||
list_fcts(sh, re_fct_exclude);
|
list_fcts(sh, re_fct_exclude);
|
||||||
else if(options["list-cmd"])
|
else if(options["list-cmd"])
|
||||||
list_cmds(sh, regex_null);
|
list_cmds(sh, regex_null);
|
||||||
// output
|
#ifdef DEBUG_MODE
|
||||||
else if(options['J'])
|
else if(options['J'])
|
||||||
{
|
{
|
||||||
std::cout << gen_json_struc(sh) << std::endl;
|
std::cout << gen_json_struc(sh) << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
// output
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// post-listing modifiers
|
// post-listing modifiers
|
||||||
|
|
@ -186,7 +193,10 @@ int main(int argc, char* argv[])
|
||||||
// processing before output
|
// processing before output
|
||||||
// minify
|
// minify
|
||||||
if(options['m'])
|
if(options['m'])
|
||||||
|
{
|
||||||
opt_minify=true;
|
opt_minify=true;
|
||||||
|
string_processors(sh);
|
||||||
|
}
|
||||||
if(options["minify-quotes"])
|
if(options["minify-quotes"])
|
||||||
minify_quotes(sh);
|
minify_quotes(sh);
|
||||||
if(options["minify-var"])
|
if(options["minify-var"])
|
||||||
|
|
@ -215,8 +225,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,11 +233,16 @@ 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;
|
||||||
|
if(sh != nullptr)
|
||||||
delete sh;
|
delete sh;
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return ERR_RUNTIME;
|
return ERR_RUNTIME;
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* escaped_char=" \\\t!\"()|&*?~";
|
const char* escaped_char=" \\\t!\"()|&*?~><";
|
||||||
const char* doublequote_escape_char=" \t'|&\\*?~";
|
const char* doublequote_escape_char=" \t'|&\\*?~><";
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,9 @@
|
||||||
#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;
|
||||||
|
|
||||||
bool g_cd=false;
|
ztd::option_set options( {
|
||||||
bool g_include=true;
|
|
||||||
bool g_resolve=true;
|
|
||||||
bool g_shebang=true;
|
|
||||||
|
|
||||||
ztd::option_set gen_options()
|
|
||||||
{
|
|
||||||
ztd::option_set ret;
|
|
||||||
ret.add(
|
|
||||||
ztd::option("\r [Help]"),
|
ztd::option("\r [Help]"),
|
||||||
ztd::option('h', "help", false, "Display this help message"),
|
ztd::option('h', "help", false, "Display this help message"),
|
||||||
ztd::option("version", false, "Display version"),
|
ztd::option("version", false, "Display version"),
|
||||||
|
|
@ -29,7 +20,10 @@ ztd::option_set gen_options()
|
||||||
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
||||||
ztd::option('e', "exec", false, "Directly execute script"),
|
ztd::option('e', "exec", false, "Directly execute script"),
|
||||||
ztd::option("no-shebang", false, "Don't output shebang"),
|
ztd::option("no-shebang", false, "Don't output shebang"),
|
||||||
|
#ifdef DEBUG_MODE
|
||||||
|
ztd::option("\r [Debugging]"),
|
||||||
ztd::option('J', "json", false, "Output the json structure"),
|
ztd::option('J', "json", false, "Output the json structure"),
|
||||||
|
#endif
|
||||||
ztd::option("\r [Processing]"),
|
ztd::option("\r [Processing]"),
|
||||||
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
||||||
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
|
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
|
||||||
|
|
@ -39,22 +33,26 @@ ztd::option_set gen_options()
|
||||||
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
||||||
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
||||||
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
||||||
ztd::option("\r [var/fct processing]"),
|
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
||||||
ztd::option("minify-var", false, "Minify variable names"),
|
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
||||||
ztd::option("minify-fct", false, "Minify function names"),
|
ztd::option("\r [Variable processing]"),
|
||||||
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
|
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("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", 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-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-var-call", false, "List all variables invoked in the script"),
|
||||||
ztd::option("list-fct", false, "List all functions defined 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("list-cmd", false, "List all commands invoked in the script"),
|
ztd::option("\r [Function processing]"),
|
||||||
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
|
||||||
ztd::option("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference")
|
ztd::option("minify-fct", false, "Minify function names"),
|
||||||
);
|
ztd::option("list-fct", false, "List all functions defined in the script")
|
||||||
return ret;
|
} );
|
||||||
}
|
|
||||||
|
bool g_cd=false;
|
||||||
|
bool g_include=true;
|
||||||
|
bool g_resolve=true;
|
||||||
|
bool g_shebang=true;
|
||||||
|
|
||||||
void get_opts()
|
void get_opts()
|
||||||
{
|
{
|
||||||
|
|
@ -102,9 +100,8 @@ ztd::option_set create_resolve_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);
|
||||||
|
|
|
||||||
1859
src/parse.cpp
1859
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
|
||||||
|
|
||||||
|
|
@ -415,6 +419,67 @@ 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)
|
||||||
|
{
|
||||||
|
string_subarg* t = dynamic_cast<string_subarg*>(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-quotes"])
|
||||||
|
minify_quotes(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 **/
|
||||||
|
|
||||||
std::string quote_string(std::string const& in)
|
std::string quote_string(std::string const& in)
|
||||||
|
|
@ -454,6 +519,7 @@ std::string boolstring(bool in)
|
||||||
return "false";
|
return "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_MODE
|
||||||
std::string gen_json_struc(_obj* o)
|
std::string gen_json_struc(_obj* o)
|
||||||
{
|
{
|
||||||
if(o==nullptr)
|
if(o==nullptr)
|
||||||
|
|
@ -781,3 +847,4 @@ std::string gen_json_struc(_obj* o)
|
||||||
}
|
}
|
||||||
return gen_json(vec);
|
return gen_json(vec);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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* 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* 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*> do_include_parse(condlist* cmd, parse_context ctx)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist*> 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,7 +186,7 @@ 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*> do_resolve_parse(condlist* cmd, parse_context ctx)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
|
@ -186,10 +195,13 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
||||||
{
|
{
|
||||||
// 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,7 +220,7 @@ 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*> , bool > resolve_condlist(condlist* in, parse_context ctx)
|
||||||
{
|
{
|
||||||
cmd* tc = in->first_cmd();
|
cmd* tc = in->first_cmd();
|
||||||
if(tc == nullptr)
|
if(tc == nullptr)
|
||||||
|
|
@ -217,14 +229,14 @@ std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, std::s
|
||||||
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*>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& filename, bool forcequote=false)
|
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, parse_context ctx, bool forcequote=false)
|
||||||
{
|
{
|
||||||
std::vector<arg*> ret;
|
std::vector<arg*> ret;
|
||||||
if(in == nullptr)
|
if(in == nullptr)
|
||||||
|
|
@ -250,12 +262,12 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
||||||
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;
|
||||||
|
|
@ -321,10 +333,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)
|
||||||
{
|
{
|
||||||
|
|
@ -337,7 +349,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
auto t = dynamic_cast<list*>(o);
|
auto t = dynamic_cast<list*>(o);
|
||||||
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_condlist(t->cls[i], *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,7 +362,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->cls[i], filename);
|
resolve(t->cls[i], ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -360,7 +372,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
auto t = dynamic_cast<arglist*>(o);
|
auto t = dynamic_cast<arglist*>(o);
|
||||||
for(uint32_t i=0 ; i<t->size() ; i++)
|
for(uint32_t i=0 ; i<t->size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_arg(t->args[i], *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,7 +384,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->args[i], filename);
|
resolve(t->args[i], ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -382,12 +394,12 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
auto t = dynamic_cast<cmd*>(o);
|
auto t = dynamic_cast<cmd*>(o);
|
||||||
for(auto it: t->var_assigns) // var assigns
|
for(auto it: t->var_assigns) // var assigns
|
||||||
{
|
{
|
||||||
resolve_arg(it.second, *filename, true); // force quoted
|
resolve_arg(it.second, *ct, true); // force quoted
|
||||||
resolve(it.second, filename);
|
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 :
|
||||||
|
|
@ -395,15 +407,15 @@ bool r_resolve(_obj* o, std::string* filename)
|
||||||
auto t = dynamic_cast<case_block*>(o);
|
auto t = dynamic_cast<case_block*>(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 +424,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", { "[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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
arg* make_arg(std::string const& in)
|
arg* 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* make_cmd(std::vector<std::string> const& args)
|
||||||
|
|
@ -34,7 +34,7 @@ cmd* make_cmd(std::vector<arg*> const& args)
|
||||||
|
|
||||||
cmd* make_cmd(std::string const& in)
|
cmd* 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* make_pipeline(std::vector<block*> const& bls)
|
||||||
|
|
@ -48,22 +48,23 @@ pipeline* make_pipeline(std::vector<block*> const& bls)
|
||||||
|
|
||||||
pipeline* make_pipeline(std::string const& in)
|
pipeline* 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* 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* 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* make_block(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_block(in.c_str(), in.size(), 0).first;
|
return parse_block(make_context(in)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -71,7 +72,7 @@ block* make_block(std::string const& in)
|
||||||
|
|
||||||
arg* copy(arg* in) {
|
arg* copy(arg* 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
|
||||||
|
|
@ -147,20 +148,47 @@ size_t cmd::arglist_size()
|
||||||
|
|
||||||
// string getters
|
// string getters
|
||||||
|
|
||||||
|
bool arg::is_string()
|
||||||
|
{
|
||||||
|
return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
|
||||||
|
}
|
||||||
|
|
||||||
std::string arg::string()
|
std::string arg::string()
|
||||||
{
|
{
|
||||||
if(sa.size() != 1 || sa[0]->type != subarg::subarg_string)
|
if(!this->is_string())
|
||||||
return "";
|
return "";
|
||||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arg::first_sa_string()
|
std::string arg::first_sa_string()
|
||||||
{
|
{
|
||||||
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string)
|
if(sa.size() <=0 || sa[0]->type != _obj::subarg_string)
|
||||||
return "";
|
return "";
|
||||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool arg::can_expand()
|
||||||
|
{
|
||||||
|
for(auto it: sa)
|
||||||
|
{
|
||||||
|
if(it->type != _obj::subarg_string && !it->quoted)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arglist::can_expand()
|
||||||
|
{
|
||||||
|
bool arg_expands=false;
|
||||||
|
for(auto it: args)
|
||||||
|
{
|
||||||
|
arg_expands = it->can_expand();
|
||||||
|
if(arg_expands)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> arglist::strargs(uint32_t start)
|
std::vector<std::string> arglist::strargs(uint32_t start)
|
||||||
{
|
{
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
|
|
|
||||||
79
src/util.cpp
79
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";
|
||||||
|
|
||||||
|
|
@ -210,16 +212,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 +233,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++;
|
||||||
}
|
}
|
||||||
}
|
std::cerr << ztd::color::b_white;
|
||||||
if(origin != "")
|
fprintf(stderr, "%s:%lu:%lu: ", e.origin(), line, index-j+1);
|
||||||
{
|
|
||||||
fprintf(stderr, "%s:%u:%u: %s\n", origin.c_str(), line, index-j+1, message.c_str());
|
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)
|
if(print_line)
|
||||||
{
|
{
|
||||||
std::cerr << std::string(in+j, i-j) << std::endl;
|
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||||
std::cerr << repeatString(" ", index-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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue