commit
3429a398cf
24 changed files with 1919 additions and 1564 deletions
61
Makefile
61
Makefile
|
|
@ -14,65 +14,76 @@ LDFLAGS = -lpthread
|
|||
# compiler
|
||||
CC=g++
|
||||
# compiler flags
|
||||
CXXFLAGS= -I$(IDIR) -Wall -pedantic -std=c++20
|
||||
CXXFLAGS= -I$(IDIR) -Wall -std=c++20
|
||||
ifeq ($(DEBUG),true)
|
||||
# debugging flags
|
||||
CC=clang++
|
||||
CXXFLAGS += -g -pg -D NO_PARSE_CATCH
|
||||
# debugging flags
|
||||
CXXFLAGS += -g -D DEBUG_MODE
|
||||
RODIR = $(ODIR)/debug
|
||||
else
|
||||
# release flags
|
||||
CXXFLAGS += -Ofast
|
||||
# release flags
|
||||
CXXFLAGS += -Ofast
|
||||
RODIR = $(ODIR)/release
|
||||
endif
|
||||
ifeq ($(STATIC),true)
|
||||
# static links
|
||||
LDFLAGS += -l:libztd.a
|
||||
else
|
||||
# dynamic links
|
||||
LDFLAGS += -lztd
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(PROFILE),true)
|
||||
CXXFLAGS += -pg
|
||||
endif
|
||||
|
||||
ifneq ($(RELEASE), true)
|
||||
VSUFFIX=-dev-$(SHA_SHORT)
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC),true)
|
||||
# static links
|
||||
LDFLAGS += -l:libztd.a
|
||||
else
|
||||
# dynamic links
|
||||
LDFLAGS += -lztd
|
||||
endif
|
||||
|
||||
## END CONFIG ##
|
||||
|
||||
|
||||
$(shell ./generate_version.sh)
|
||||
$(shell ./generate_shellcode.sh)
|
||||
$(shell mkdir -p $(ODIR))
|
||||
|
||||
$(shell mkdir -p $(RODIR))
|
||||
$(shell mkdir -p $(BINDIR))
|
||||
|
||||
# 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
|
||||
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 $@ $<
|
||||
|
||||
$(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||
$(OBJDIR)/shellcode.o: $(SRCDIR)/shellcode.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
||||
$(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 $@ $<
|
||||
|
||||
$(ODIR)/shellcode.o: $(SRCDIR)/shellcode.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
||||
# generic files
|
||||
|
||||
$(RODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
|
||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(ODIR)/debashify.o: $(SRCDIR)/debashify.cpp $(DEPS) $(IDIR)/g_shellcode.h
|
||||
$(RODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
lxsh: $(OBJ)
|
||||
|
||||
$(BINDIR)/$(NAME): $(OBJ)
|
||||
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test: $(BINDIR)/$(NAME)
|
||||
$(BINDIR)/$(NAME)
|
||||
|
||||
clean:
|
||||
rm $(ODIR)/*.o gmon.out
|
||||
rm $(ODIR)/*/*.o
|
||||
|
||||
clear:
|
||||
rm $(BINDIR)/$(NAME)
|
||||
|
|
|
|||
23
README.md
23
README.md
|
|
@ -8,7 +8,7 @@ Extended shell linker for linking, processing and minifying shell code
|
|||
|
||||
### zpkg
|
||||
|
||||
Available from the `zpkg` repository:
|
||||
Available from the [zpkg](https://github.com/zawwz/zpkg) repository:
|
||||
```shell
|
||||
wget -qO- https://zpkg.zawz.net/install.sh | sh
|
||||
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).
|
||||
|
||||
```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
|
||||
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.
|
||||
|
||||
## 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
|
||||
|
||||
### Output generated code
|
||||
|
|
@ -154,7 +171,7 @@ Depends on [ztd](https://github.com/zawwz/ztd)
|
|||
|
||||
## Building
|
||||
|
||||
Use `make -j13` to build.<br>
|
||||
Use `make -j` to build.<br>
|
||||
You can use environment variables to alter some aspects:
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
|
||||
typedef struct debashify_params {
|
||||
struct debashify_params {
|
||||
std::set<std::string> required_fcts;
|
||||
void require_fct(std::string const& in) { required_fcts.insert(in); }
|
||||
// map of detected arrays
|
||||
// bool value: is associative
|
||||
std::map<std::string,bool> arrays;
|
||||
} debashify_params;
|
||||
};
|
||||
|
||||
bool r_debashify(_obj* o, debashify_params* params);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef ERRCODES_H
|
||||
#define ERRCODES_H
|
||||
|
||||
#define ERR_HELP 1001
|
||||
#define ERR_OPT 1002
|
||||
#define ERR_PARSE 1003
|
||||
#define ERR_RUNTIME 1004
|
||||
#define ERR_HELP 101
|
||||
#define ERR_OPT 102
|
||||
#define ERR_PARSE 103
|
||||
#define ERR_RUNTIME 104
|
||||
|
||||
#endif //ERRCODES_H
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
#define EXEC_HPP
|
||||
|
||||
#include "options.hpp"
|
||||
#include "parse.hpp"
|
||||
|
||||
|
||||
void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& filename="");
|
||||
inline void parse_exec(FILE* fd, std::string const& in, std::string const& filename="") { parse_exec(fd, in.c_str(), in.size(), filename); }
|
||||
void parse_exec(FILE* fd, parse_context ct);
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <ztd/filedat.hpp>
|
||||
#include <tuple>
|
||||
|
||||
#define SPACES " \t"
|
||||
#define SEPARATORS " \t\n"
|
||||
#define ARG_END " \t\n;#()&|<>"
|
||||
#define VARNAME_END " \t\n;#()&|=\"'\\{}/-+"
|
||||
#define BLOCK_TOKEN_END " \t\n;#()&|=\"'\\"
|
||||
#define BASH_BLOCK_END " \t\n;#()&|=\"'\\{}"
|
||||
#define COMMAND_SEPARATOR "\n;"
|
||||
#define CONTROL_END "#)"
|
||||
#define PIPELINE_END "\n;#()&"
|
||||
|
|
@ -27,59 +27,94 @@
|
|||
#define ARRAY_ARG_END " \t\n;#()&|<>]"
|
||||
|
||||
// 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
|
||||
|
||||
extern bool g_bash;
|
||||
|
||||
extern const std::vector<std::string> posix_cmdvar;
|
||||
extern const std::vector<std::string> bash_cmdvar;
|
||||
|
||||
std::string import_file(std::string const& path);
|
||||
|
||||
shmain* parse_text(const char* in, uint32_t size, std::string const& filename="");
|
||||
inline shmain* parse_text(std::string const& in, std::string const& filename="") { return parse_text(in.c_str(), in.size(), filename); }
|
||||
inline shmain* parse(std::string const& file) { return parse_text(import_file(file), file); }
|
||||
std::pair<shmain*, parse_context> parse_text(parse_context context);
|
||||
std::pair<shmain*, parse_context> parse_text(std::string const& in, std::string const& filename="");
|
||||
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 ** //
|
||||
|
||||
/* util parsers */
|
||||
bool 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);
|
||||
uint32_t word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set=NULL);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
inline uint32_t skip_unread(parse_context const& ct) {
|
||||
return skip_unread(ct.data, ct.size, ct.i);
|
||||
}
|
||||
|
||||
// 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*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
|
||||
std::tuple<list*, uint32_t, std::string> parse_list_until(const char* in, uint32_t size, uint32_t start, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
||||
// std::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL);
|
||||
// std::pair<list*, parse_context> parse_list_until(parse_context ct, std::string const& end_word);
|
||||
// std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
||||
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
|
||||
// name
|
||||
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
|
||||
std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<variable*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<arithmetic*, parse_context> parse_arithmetic(parse_context ct);
|
||||
std::pair<variable*, parse_context> parse_manipulation(parse_context ct);
|
||||
// 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
|
||||
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
|
||||
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
|
||||
std::pair<block*, uint32_t> parse_block(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<cmd*, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<function*, uint32_t> parse_function(const char* in, uint32_t size, uint32_t start, const char* after="()");
|
||||
std::pair<subshell*, uint32_t> parse_subshell(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<brace*, uint32_t> parse_brace(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<case_block*, uint32_t> parse_case(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<if_block*, uint32_t> parse_if(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<for_block*, uint32_t> parse_for(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<while_block*, uint32_t> parse_while(const char* in, uint32_t size, uint32_t start);
|
||||
std::pair<block*, parse_context> parse_block(parse_context ct);
|
||||
std::pair<cmd*, parse_context> parse_cmd(parse_context ct);
|
||||
std::pair<function*, parse_context> parse_function(parse_context ct, const char* after="()");
|
||||
std::pair<subshell*, parse_context> parse_subshell(parse_context ct);
|
||||
std::pair<brace*, parse_context> parse_brace(parse_context ct);
|
||||
std::pair<case_block*, parse_context> parse_case(parse_context ct);
|
||||
std::pair<if_block*, parse_context> parse_if(parse_context ct);
|
||||
std::pair<for_block*, parse_context> parse_for(parse_context ct);
|
||||
std::pair<while_block*, parse_context> parse_while(parse_context ct);
|
||||
// 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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -76,4 +76,6 @@ bool r_delete_var(_obj* in, set_t* vars);
|
|||
std::set<std::string> find_lxsh_commands(shmain* sh);
|
||||
void add_unset_variables(shmain* sh, std::regex const& exclude);
|
||||
|
||||
void string_processors(_obj* in);
|
||||
|
||||
#endif //PROCESSING_HPP
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
#define RESOLVE_HPP
|
||||
|
||||
#include "struc.hpp"
|
||||
#include "parse.hpp"
|
||||
|
||||
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::pair<std::string, std::string> do_resolve_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, parse_context ctx, std::string* ex_dir=nullptr);
|
||||
|
||||
bool add_include(std::string const& file);
|
||||
|
||||
void resolve(_obj* sh, std::string* filename);
|
||||
void resolve(shmain* sh);
|
||||
void resolve(_obj* sh, parse_context ctx);
|
||||
|
||||
std::string _pre_cd(std::string const& filename);
|
||||
void _cd(std::string const& dir);
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ struct lxsh_fct {
|
|||
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 struct 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_extend_fcts;
|
||||
extern const std::map<const std::string, const lxsh_fct> lxsh_array_fcts;
|
||||
extern const std::map<const std::string, const lxsh_fct> lxsh_allfcts;
|
||||
|
||||
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 OR_OP true
|
||||
|
||||
|
|
@ -71,6 +73,56 @@ class pipeline;
|
|||
class arg;
|
||||
class subarg;
|
||||
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
|
||||
typedef std::vector<arg*> arglist_t;
|
||||
|
|
@ -135,11 +187,15 @@ public:
|
|||
|
||||
std::vector<subarg*> sa;
|
||||
|
||||
bool is_string();
|
||||
// return if is a string and only one subarg
|
||||
std::string string();
|
||||
// return if the first subarg is a 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; }
|
||||
|
||||
std::string generate(int ind);
|
||||
|
|
@ -179,6 +235,9 @@ public:
|
|||
|
||||
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, arglist const& lst);
|
||||
|
||||
|
|
@ -190,15 +249,20 @@ public:
|
|||
class redirect : public _obj
|
||||
{
|
||||
public:
|
||||
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; }
|
||||
redirect(arg* in) { type=_obj::_redirect; target=in; }
|
||||
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; }
|
||||
~redirect() { if(target != nullptr) delete target; }
|
||||
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; here_document=nullptr; }
|
||||
redirect(arg* in) { type=_obj::_redirect; target=in; here_document=nullptr; }
|
||||
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; here_document=nullptr; }
|
||||
redirect(std::string strop, arg* in, arg* doc) { type=_obj::_redirect; op=strop; target=in; here_document=doc; }
|
||||
~redirect() {
|
||||
if(target != nullptr) delete target;
|
||||
if(here_document != nullptr) delete here_document;
|
||||
}
|
||||
|
||||
std::string generate(int ind);
|
||||
|
||||
std::string op;
|
||||
arg* target;
|
||||
arg* here_document;
|
||||
};
|
||||
|
||||
// Meta block
|
||||
|
|
@ -213,9 +277,9 @@ public:
|
|||
// subshell: return the containing cmd, if it is a single command
|
||||
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
|
||||
|
|
@ -230,7 +294,8 @@ public:
|
|||
|
||||
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
|
||||
|
|
@ -331,7 +396,8 @@ public:
|
|||
|
||||
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
|
||||
|
|
@ -349,7 +415,8 @@ public:
|
|||
list* lst;
|
||||
|
||||
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
|
||||
|
|
@ -365,7 +432,8 @@ public:
|
|||
|
||||
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
|
||||
|
|
@ -380,7 +448,8 @@ public:
|
|||
|
||||
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
|
||||
|
|
@ -394,7 +463,8 @@ public:
|
|||
std::string name;
|
||||
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
|
||||
|
|
@ -414,7 +484,8 @@ public:
|
|||
arg* carg;
|
||||
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
|
||||
|
|
@ -434,7 +505,8 @@ public:
|
|||
|
||||
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
|
||||
|
|
@ -452,7 +524,8 @@ public:
|
|||
arglist* iter;
|
||||
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
|
||||
|
|
@ -469,7 +542,8 @@ public:
|
|||
list* cond;
|
||||
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 //
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
#include <functional>
|
||||
#include <regex>
|
||||
|
||||
#include <ztd/filedat.hpp>
|
||||
|
||||
#include "struc.hpp"
|
||||
|
||||
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);
|
||||
|
||||
void printFormatError(ztd::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);
|
||||
void printFormatError(format_error const& e, bool print_line=true);
|
||||
|
||||
#endif //UTIL_HPP
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_STRING "v1.1.0"
|
||||
#define VERSION_STRING "v1.2.0"
|
||||
|
||||
#endif //VERSION_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "debashify.hpp"
|
||||
|
||||
#include "ztd/options.hpp"
|
||||
#include <ztd/options.hpp>
|
||||
|
||||
#include "processing.hpp"
|
||||
#include "recursive.hpp"
|
||||
|
|
@ -144,12 +144,11 @@ std::string get_declare_opt(cmd* in)
|
|||
|
||||
ztd::option_set gen_echo_opts()
|
||||
{
|
||||
ztd::option_set ret;
|
||||
ret.add(
|
||||
ztd::option('e'),
|
||||
ztd::option('E'),
|
||||
ztd::option('n')
|
||||
);
|
||||
ztd::option_set ret( std::vector<ztd::option>({
|
||||
ztd::option('e'),
|
||||
ztd::option('E'),
|
||||
ztd::option('n')
|
||||
}) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -166,60 +165,124 @@ bool debashify_echo(pipeline* pl)
|
|||
ztd::option_set opts=gen_echo_opts();
|
||||
std::vector<std::string> args=in->args->strargs(1);
|
||||
std::vector<std::string> postargs;
|
||||
|
||||
try
|
||||
{
|
||||
postargs=opts.process(args, true, true);
|
||||
postargs=opts.process(args, {.ignore_numbers=true, .stop_on_argument=true} );
|
||||
}
|
||||
catch(ztd::option_error& e)
|
||||
{
|
||||
skip=true;
|
||||
}
|
||||
if(skip || postargs.size() == args.size()) // no options processed: skip
|
||||
return false;
|
||||
|
||||
// delete the number of args that were processed
|
||||
for(uint32_t i=0; i<args.size()-postargs.size(); i++)
|
||||
{
|
||||
delete in->args->args[1];
|
||||
in->args->args.erase(in->args->args.begin()+1);
|
||||
}
|
||||
|
||||
bool doprintf=false;
|
||||
bool enable_interpretation=false;
|
||||
bool newline=true;
|
||||
if(opts['E'])
|
||||
bool has_escape_sequence=false;
|
||||
bool has_processed_options=false;
|
||||
|
||||
if(!skip && postargs.size() != args.size())
|
||||
{
|
||||
doprintf=true;
|
||||
}
|
||||
else if(opts['n'])
|
||||
{
|
||||
doprintf=true;
|
||||
newline=false;
|
||||
has_processed_options=true;
|
||||
// delete the number of args that were processed
|
||||
for(uint32_t i=0; i<args.size()-postargs.size(); i++)
|
||||
{
|
||||
delete in->args->args[1];
|
||||
in->args->args.erase(in->args->args.begin()+1);
|
||||
}
|
||||
|
||||
if(opts['e'])
|
||||
enable_interpretation=true;
|
||||
else if(opts['n'])
|
||||
newline=false;
|
||||
}
|
||||
|
||||
if(doprintf)
|
||||
for(auto it=in->args->args.begin()+1; it!=in->args->args.end(); it++)
|
||||
{
|
||||
delete in->args->args[0];
|
||||
in->args->args[0] = new arg("printf");
|
||||
if(possibly_expands(in->args->args[2]) )
|
||||
if(!(*it)->is_string() || (*it)->string().find('\\') != std::string::npos)
|
||||
{
|
||||
in->args->insert(1, new arg("%s\\ "));
|
||||
if(newline) // newline: add a newline command at the end
|
||||
has_escape_sequence=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(newline && !has_escape_sequence)
|
||||
{
|
||||
// newline and no potential escape: don't replace, keep echo
|
||||
return has_processed_options;
|
||||
}
|
||||
else
|
||||
{
|
||||
// replace by printf
|
||||
if(!in->args->can_expand())
|
||||
{
|
||||
// no potential expansion: static number of args
|
||||
std::string format_str = "'";
|
||||
for(uint32_t i=1; i<in->args->args.size(); i++)
|
||||
{
|
||||
brace* br = new brace(new list);
|
||||
br->lst->add(new condlist(in));
|
||||
br->lst->add(make_condlist("echo"));
|
||||
pl->cmds[0] = br;
|
||||
if(enable_interpretation)
|
||||
format_str += "%b ";
|
||||
else
|
||||
format_str += "%s ";
|
||||
}
|
||||
format_str.pop_back();
|
||||
if(newline)
|
||||
format_str += "\\n";
|
||||
format_str += '\'';
|
||||
|
||||
in->args->insert(1, new arg(format_str));
|
||||
delete in->args->args[0];
|
||||
in->args->args[0] = new arg("printf");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string printfarg="'%s";
|
||||
for(uint32_t i=2; i<in->args->size(); i++)
|
||||
printfarg+=" %s";
|
||||
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)
|
||||
printfarg+="\\n";
|
||||
printfarg+="'";
|
||||
in->args->insert(1, new arg(printfarg));
|
||||
{
|
||||
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.pop_back();
|
||||
// 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 first argument is _lxsh_X_create
|
||||
if(params->arrays[varname])
|
||||
|
|
@ -569,7 +632,7 @@ bool debashify_array_set(cmd* in, debashify_params* params)
|
|||
gen=gen.substr(3);
|
||||
gen.pop_back();
|
||||
// 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 first argument is _lxsh_array_create
|
||||
if(params->arrays[varname])
|
||||
|
|
|
|||
129
src/exec.cpp
129
src/exec.cpp
|
|
@ -18,16 +18,16 @@
|
|||
#define PIPE_READ 0
|
||||
#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::string dir;
|
||||
auto incs=do_include_raw(cmd, filename, &dir);
|
||||
auto incs=do_include_raw(cmd, ctx, &dir);
|
||||
|
||||
for(auto it: incs)
|
||||
{
|
||||
parse_exec(fd, it.second, it.first);
|
||||
parse_exec(fd, make_context(ctx, it.second, it.first));
|
||||
}
|
||||
// cd back
|
||||
_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
|
||||
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;
|
||||
|
||||
|
|
@ -45,15 +45,15 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filenam
|
|||
{
|
||||
// get
|
||||
std::string dir;
|
||||
p=do_resolve_raw(cmd, filename, &dir);
|
||||
p=do_resolve_raw(cmd, ctx, &dir);
|
||||
// do parse
|
||||
parse_exec(fd, p.second, filename);
|
||||
parse_exec(fd, make_context(ctx, p.second, p.first));
|
||||
// cd back
|
||||
_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;
|
||||
|
|
@ -61,7 +61,7 @@ std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filenam
|
|||
|
||||
// -- 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();
|
||||
if(tc == nullptr)
|
||||
|
|
@ -71,23 +71,23 @@ bool resolve_condlist_exec(condlist* in, std::string const& filename, FILE* fd)
|
|||
|
||||
if(g_include && strcmd == "%include")
|
||||
{
|
||||
do_include_exec(in, filename, fd);
|
||||
do_include_exec(in, ctx, fd);
|
||||
return true;
|
||||
}
|
||||
else if(g_resolve && strcmd == "%resolve")
|
||||
{
|
||||
do_resolve_exec(in, filename, fd);
|
||||
do_resolve_exec(in, ctx, fd);
|
||||
return true;
|
||||
}
|
||||
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 true;
|
||||
|
|
@ -138,60 +138,57 @@ std::string random_string()
|
|||
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);
|
||||
#ifndef NO_PARSE_CATCH
|
||||
try
|
||||
ctx.i=skip_unread(ctx);
|
||||
|
||||
debashify_params debash_params;
|
||||
list* t_lst=new list;
|
||||
if(t_lst == nullptr)
|
||||
throw std::runtime_error("Alloc error");
|
||||
while(ctx.i<ctx.size)
|
||||
{
|
||||
#endif
|
||||
;
|
||||
debashify_params debash_params;
|
||||
list* t_lst=new list;
|
||||
if(t_lst == nullptr)
|
||||
throw std::runtime_error("Alloc error");
|
||||
while(i<size)
|
||||
auto pp=parse_condlist(ctx);
|
||||
ctx=pp.second;
|
||||
if(ctx.has_errored)
|
||||
{
|
||||
auto pp=parse_condlist(in, size, i);
|
||||
i=pp.second;
|
||||
t_lst->add(pp.first);
|
||||
if(g_resolve || g_include)
|
||||
parse_list_until(ctx);
|
||||
throw std::runtime_error("Aborting due to previous errors");
|
||||
}
|
||||
t_lst->add(pp.first);
|
||||
if(g_resolve || g_include)
|
||||
{
|
||||
if(resolve_exec(t_lst->cls[0], ctx, fd))
|
||||
{
|
||||
if(resolve_exec(t_lst->cls[0], filename, fd))
|
||||
{
|
||||
t_lst->clear();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(options["debashify"])
|
||||
debashify(t_lst, &debash_params);
|
||||
|
||||
|
||||
std::string gen=t_lst->generate(0);
|
||||
t_lst->clear();
|
||||
|
||||
fprintf(fd, "%s", gen.c_str());
|
||||
|
||||
if(i < size)
|
||||
{
|
||||
if(in[i] == '#')
|
||||
; // skip here
|
||||
else if(is_in(in[i], COMMAND_SEPARATOR))
|
||||
i++; // skip on next char
|
||||
else if(is_in(in[i], CONTROL_END))
|
||||
throw PARSE_ERROR(strf("Unexpected token: '%c'", in[i]), i);
|
||||
|
||||
i = skip_unread(in, size, i);
|
||||
t_lst->clear();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
delete t_lst;
|
||||
#ifndef NO_PARSE_CATCH
|
||||
}
|
||||
catch(ztd::format_error& e)
|
||||
{
|
||||
throw ztd::format_error(e.what(), filename, in, e.where());
|
||||
if(options["debashify"])
|
||||
debashify(t_lst, &debash_params);
|
||||
|
||||
|
||||
std::string gen=t_lst->generate(0);
|
||||
t_lst->clear();
|
||||
|
||||
fprintf(fd, "%s", gen.c_str());
|
||||
|
||||
if(ctx.i < ctx.size)
|
||||
{
|
||||
if(ctx[ctx.i] == '#')
|
||||
; // skip here
|
||||
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||
ctx.i++; // skip on next char
|
||||
else if(is_in(ctx[ctx.i], CONTROL_END))
|
||||
{
|
||||
format_error(strf("Unexpected token: '%c'", ctx[ctx.i]), ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.i = skip_unread(ctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
delete t_lst;
|
||||
}
|
||||
|
||||
pid_t forkexec(const char* bin, char *const args[])
|
||||
|
|
@ -205,10 +202,6 @@ pid_t forkexec(const char* bin, char *const args[])
|
|||
}
|
||||
if (child_pid == 0) // child process
|
||||
{
|
||||
// char buf[1000] = {0};
|
||||
// read(STDIN_FILENO, buf, 1000);
|
||||
// std::cout << std::string(buf) << std::endl;
|
||||
// std::cout << dup2(tfd, STDIN_FILENO) << std::endl;
|
||||
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
|
||||
execv(bin, args);
|
||||
throw std::runtime_error("execv() failed");
|
||||
|
|
@ -234,7 +227,7 @@ int wait_pid(pid_t pid)
|
|||
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<char*> runargs;
|
||||
|
|
@ -254,8 +247,6 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
|
|||
runargs.push_back(NULL);
|
||||
|
||||
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;
|
||||
try
|
||||
{
|
||||
|
|
@ -268,7 +259,7 @@ int exec_process(std::string const& runtime, std::vector<std::string> const& arg
|
|||
}
|
||||
for(auto it: lxsh_extend_fcts)
|
||||
fprintf(ffd, "%s\n", it.second.code);
|
||||
parse_exec(ffd, filecontents, file);
|
||||
parse_exec(ffd, ctx);
|
||||
}
|
||||
catch(std::runtime_error& e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ std::string arglist::generate(int ind)
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::string pipeline::generate(int ind)
|
||||
std::string pipeline::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
|
|
@ -53,11 +53,11 @@ std::string pipeline::generate(int ind)
|
|||
|
||||
if(negated)
|
||||
ret += "! ";
|
||||
ret += cmds[0]->generate(ind);
|
||||
ret += cmds[0]->generate(ind, ctx);
|
||||
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
||||
{
|
||||
ret += opt_minify ? "|" : " | " ;
|
||||
ret += cmds[i]->generate(ind);
|
||||
ret += cmds[i]->generate(ind, ctx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -68,18 +68,27 @@ std::string condlist::generate(int ind)
|
|||
std::string ret;
|
||||
if(pls.size() <= 0)
|
||||
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++)
|
||||
{
|
||||
if(or_ops[i])
|
||||
ret += opt_minify ? "||" : " || ";
|
||||
else
|
||||
ret += opt_minify ? "&&" : " && ";
|
||||
ret += pls[i+1]->generate(ind);
|
||||
ret += pls[i+1]->generate(ind, &ctx);
|
||||
}
|
||||
if(ret=="")
|
||||
return "";
|
||||
if(parallel)
|
||||
if(ctx.here_document != nullptr)
|
||||
{
|
||||
if(parallel)
|
||||
ret += '&';
|
||||
ret += '\n';
|
||||
ret += ctx.here_document->generate(0);
|
||||
ret += '\n';
|
||||
}
|
||||
else if(parallel)
|
||||
{
|
||||
ret += opt_minify ? "&" : " &\n";
|
||||
}
|
||||
|
|
@ -123,12 +132,18 @@ std::string redirect::generate(int ind)
|
|||
|
||||
// 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=" ";
|
||||
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
||||
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);
|
||||
if(opt_minify && _r.size() > 0 && !is_num(_r[0]) && previous_isnt_num)
|
||||
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;
|
||||
}
|
||||
|
||||
std::string if_block::generate(int ind)
|
||||
std::string if_block::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
|
|
@ -169,11 +184,11 @@ std::string if_block::generate(int ind)
|
|||
|
||||
ret += indented("fi", ind);
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string for_block::generate(int ind)
|
||||
std::string for_block::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
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]))
|
||||
ret.pop_back();
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string while_block::generate(int ind)
|
||||
std::string while_block::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
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]))
|
||||
ret.pop_back();
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string subshell::generate(int ind)
|
||||
std::string subshell::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
// open subshell
|
||||
|
|
@ -224,11 +239,11 @@ std::string subshell::generate(int ind)
|
|||
// close subshell
|
||||
ret += indented(")", ind);
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string shmain::generate(int ind)
|
||||
std::string shmain::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
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')
|
||||
ret.pop_back();
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string brace::generate(int ind)
|
||||
std::string brace::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
|
|
@ -253,11 +267,11 @@ std::string brace::generate(int ind)
|
|||
ret += lst->generate(ind+1);
|
||||
ret += indented("}", ind);
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string function::generate(int ind)
|
||||
std::string function::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
// function definition
|
||||
|
|
@ -268,11 +282,11 @@ std::string function::generate(int ind)
|
|||
ret += lst->generate(ind+1);
|
||||
ret += indented("}", ind);
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string case_block::generate(int ind)
|
||||
std::string case_block::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
ret += "case " + carg->generate(ind) + " in\n";
|
||||
|
|
@ -292,27 +306,30 @@ std::string case_block::generate(int ind)
|
|||
// end of case: ;;
|
||||
if(opt_minify && ret[ret.size()-1] == '\n') // ;; can be right after command
|
||||
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)
|
||||
{
|
||||
ret.erase(ret.size()-3, 2);
|
||||
ret.pop_back();
|
||||
}
|
||||
|
||||
// close case
|
||||
ind--;
|
||||
ret += indented("esac", ind);
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string cmd::generate(int ind)
|
||||
std::string cmd::generate(int ind, generate_context* ctx)
|
||||
{
|
||||
std::string ret;
|
||||
// var assigns
|
||||
|
||||
// is a varassign cmd
|
||||
if(is_cmdvar)
|
||||
{
|
||||
ret += args->generate(ind) + ' ';
|
||||
|
|
@ -328,6 +345,7 @@ std::string cmd::generate(int ind)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// pre-cmd var assigns
|
||||
for(auto it: var_assigns)
|
||||
{
|
||||
if(it.first != nullptr)
|
||||
|
|
@ -337,6 +355,7 @@ std::string cmd::generate(int ind)
|
|||
ret += ' ';
|
||||
}
|
||||
|
||||
// cmd itself
|
||||
if(args!=nullptr && args->size()>0)
|
||||
{
|
||||
// command
|
||||
|
|
@ -351,7 +370,7 @@ std::string cmd::generate(int ind)
|
|||
ret.pop_back();
|
||||
}
|
||||
|
||||
ret += generate_redirs(ind, ret);
|
||||
ret += generate_redirs(ind, ret, ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
110
src/main.cpp
110
src/main.cpp
|
|
@ -1,12 +1,13 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <ztd/options.hpp>
|
||||
#include <ztd/shell.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "struc.hpp"
|
||||
#include "parse.hpp"
|
||||
|
|
@ -29,6 +30,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
bool optstop=false;
|
||||
|
||||
shmain *sh=nullptr, *tsh=nullptr;
|
||||
try
|
||||
{
|
||||
args=options.process(argc, argv, {.stop_on_argument=true, .output_doubledash=true} );
|
||||
|
|
@ -37,53 +39,49 @@ int main(int argc, char* argv[])
|
|||
optstop=true;
|
||||
args.erase(args.begin());
|
||||
}
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
return ERR_OPT;
|
||||
}
|
||||
|
||||
oneshot_opt_process(argv[0]);
|
||||
|
||||
// resolve input
|
||||
std::string file;
|
||||
if(args.size() > 0) // argument provided
|
||||
{
|
||||
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
|
||||
oneshot_opt_process(argv[0]);
|
||||
|
||||
// resolve input
|
||||
std::string file;
|
||||
if(args.size() > 0) // argument provided
|
||||
{
|
||||
file = "/dev/stdin";
|
||||
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
|
||||
{
|
||||
file = "/dev/stdin";
|
||||
}
|
||||
else
|
||||
{
|
||||
file=args[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file=args[0];
|
||||
if(isatty(fileno(stdin))) // stdin is interactive
|
||||
{
|
||||
print_help(argv[0]);
|
||||
return ERR_HELP;
|
||||
}
|
||||
else // is piped
|
||||
{
|
||||
file = "/dev/stdin";
|
||||
args.push_back("/dev/stdin");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isatty(fileno(stdin))) // stdin is interactive
|
||||
{
|
||||
print_help(argv[0]);
|
||||
return ERR_HELP;
|
||||
}
|
||||
else // is piped
|
||||
{
|
||||
file = "/dev/stdin";
|
||||
args.push_back("/dev/stdin");
|
||||
}
|
||||
}
|
||||
|
||||
// parsing
|
||||
// parsing
|
||||
|
||||
sh = new shmain(new list);
|
||||
|
||||
shmain* sh = new shmain(new list);
|
||||
shmain* tsh = nullptr;
|
||||
try
|
||||
{
|
||||
bool is_exec = false;
|
||||
bool first_run = true;
|
||||
|
||||
// do parsing
|
||||
bool shebang_is_bin=false;
|
||||
bool parse_bash=false;
|
||||
parse_context ctx;
|
||||
std::string binshebang;
|
||||
for(uint32_t i=0 ; i<args.size() ; i++)
|
||||
{
|
||||
std::string file = args[i];
|
||||
|
|
@ -96,7 +94,9 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
first_run=false;
|
||||
// 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
|
||||
if(options['e'])
|
||||
|
|
@ -113,7 +113,10 @@ int main(int argc, char* argv[])
|
|||
throw std::runtime_error("Option -e must be before file");
|
||||
|
||||
if(shebang_is_bin) // enable debashify option
|
||||
{
|
||||
shebang="#!/bin/sh";
|
||||
options["debashify"].activated=true;
|
||||
}
|
||||
|
||||
oneshot_opt_process(argv[0]);
|
||||
get_opts();
|
||||
|
|
@ -124,25 +127,27 @@ int main(int argc, char* argv[])
|
|||
if(!add_include(file))
|
||||
continue;
|
||||
|
||||
ctx.data=filecontents.data();
|
||||
|
||||
|
||||
ctx = make_context(filecontents, file, parse_bash);
|
||||
if(is_exec)
|
||||
{
|
||||
if(options["debashify"])
|
||||
shebang = "#!/bin/sh";
|
||||
if(options["debashify"] || basename(shebang) == "bash")
|
||||
g_bash = true;
|
||||
args.erase(args.begin());
|
||||
return exec_process(shebang.substr(2), args, filecontents, file);
|
||||
return exec_process(shebang.substr(2), args, ctx);
|
||||
}
|
||||
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
|
||||
tsh->shebang="#!/bin/sh";
|
||||
|
||||
/* mid processing */
|
||||
// resolve/include
|
||||
if(g_include || g_resolve)
|
||||
resolve(tsh);
|
||||
resolve(tsh, ctx);
|
||||
|
||||
// concatenate to main
|
||||
sh->concat(tsh);
|
||||
|
|
@ -166,11 +171,13 @@ int main(int argc, char* argv[])
|
|||
list_fcts(sh, re_fct_exclude);
|
||||
else if(options["list-cmd"])
|
||||
list_cmds(sh, regex_null);
|
||||
// output
|
||||
#ifdef DEBUG_MODE
|
||||
else if(options['J'])
|
||||
{
|
||||
std::cout << gen_json_struc(sh) << std::endl;
|
||||
}
|
||||
#endif
|
||||
// output
|
||||
else
|
||||
{
|
||||
// post-listing modifiers
|
||||
|
|
@ -186,7 +193,10 @@ int main(int argc, char* argv[])
|
|||
// processing before output
|
||||
// minify
|
||||
if(options['m'])
|
||||
{
|
||||
opt_minify=true;
|
||||
string_processors(sh);
|
||||
}
|
||||
if(options["minify-quotes"])
|
||||
minify_quotes(sh);
|
||||
if(options["minify-var"])
|
||||
|
|
@ -215,8 +225,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifndef NO_PARSE_CATCH
|
||||
catch(ztd::format_error& e)
|
||||
catch(format_error& e)
|
||||
{
|
||||
if(tsh != nullptr)
|
||||
delete tsh;
|
||||
|
|
@ -224,12 +233,17 @@ int main(int argc, char* argv[])
|
|||
printFormatError(e);
|
||||
return ERR_PARSE;
|
||||
}
|
||||
#endif
|
||||
catch(ztd::option_error& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
return ERR_OPT;
|
||||
}
|
||||
catch(std::runtime_error& e)
|
||||
{
|
||||
if(tsh != nullptr)
|
||||
delete tsh;
|
||||
delete sh;
|
||||
if(sh != nullptr)
|
||||
delete sh;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return ERR_RUNTIME;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
|
|||
return true;
|
||||
}
|
||||
|
||||
const char* escaped_char=" \\\t!\"()|&*?~";
|
||||
const char* doublequote_escape_char=" \t'|&\\*?~";
|
||||
const char* escaped_char=" \\\t!\"()|&*?~><";
|
||||
const char* doublequote_escape_char=" \t'|&\\*?~><";
|
||||
uint32_t count_escape_chars(std::string const& in, bool doublequote)
|
||||
{
|
||||
uint32_t r=0;
|
||||
|
|
|
|||
|
|
@ -7,55 +7,53 @@
|
|||
#include "version.h"
|
||||
#include "g_version.h"
|
||||
|
||||
ztd::option_set options = gen_options();
|
||||
bool opt_minify=false;
|
||||
|
||||
ztd::option_set options( {
|
||||
ztd::option("\r [Help]"),
|
||||
ztd::option('h', "help", false, "Display this help message"),
|
||||
ztd::option("version", false, "Display version"),
|
||||
ztd::option("help-link-commands", false, "Print help for linker commands"),
|
||||
ztd::option("help-extend-fcts", false, "Print help for lxsh extension functions"),
|
||||
ztd::option("\r [Output]"),
|
||||
ztd::option('o', "output", true , "Output result script to file", "file"),
|
||||
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
||||
ztd::option('e', "exec", false, "Directly execute script"),
|
||||
ztd::option("no-shebang", false, "Don't output shebang"),
|
||||
#ifdef DEBUG_MODE
|
||||
ztd::option("\r [Debugging]"),
|
||||
ztd::option('J', "json", false, "Output the json structure"),
|
||||
#endif
|
||||
ztd::option("\r [Processing]"),
|
||||
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
||||
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
|
||||
ztd::option("minify-quotes", false, "Remove unnecessary quotes"),
|
||||
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
|
||||
ztd::option('I', "no-include", false, "Don't resolve %include commands"),
|
||||
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
||||
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
||||
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
||||
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
||||
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
||||
ztd::option("\r [Variable processing]"),
|
||||
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
|
||||
ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"),
|
||||
ztd::option("minify-var", false, "Minify variable names"),
|
||||
ztd::option("list-var", false, "List all variables set and invoked in the script"),
|
||||
ztd::option("list-var-def", false, "List all variables set in the script"),
|
||||
ztd::option("list-var-call", false, "List all variables invoked in the script"),
|
||||
ztd::option("unset-var", false, "Add 'unset' to all variables at the start of the script to avoid environment interference"),
|
||||
ztd::option("\r [Function processing]"),
|
||||
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
|
||||
ztd::option("minify-fct", false, "Minify function names"),
|
||||
ztd::option("list-fct", false, "List all functions defined in the script")
|
||||
} );
|
||||
|
||||
bool g_cd=false;
|
||||
bool g_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('h', "help", false, "Display this help message"),
|
||||
ztd::option("version", false, "Display version"),
|
||||
ztd::option("help-link-commands", false, "Print help for linker commands"),
|
||||
ztd::option("help-extend-fcts", false, "Print help for lxsh extension functions"),
|
||||
ztd::option("\r [Output]"),
|
||||
ztd::option('o', "output", true , "Output result script to file", "file"),
|
||||
ztd::option('c', "stdout", false, "Output result script to stdout"),
|
||||
ztd::option('e', "exec", false, "Directly execute script"),
|
||||
ztd::option("no-shebang", false, "Don't output shebang"),
|
||||
ztd::option('J', "json", false, "Output the json structure"),
|
||||
ztd::option("\r [Processing]"),
|
||||
ztd::option('m', "minify", false, "Minify code without changing functionality"),
|
||||
ztd::option('M', "minify-full", false, "Enable all minifying features: -m --minify-quotes --minify-var --minify-fct --remove-unused"),
|
||||
ztd::option("minify-quotes", false, "Remove unnecessary quotes"),
|
||||
ztd::option('C', "no-cd", false, "Don't cd when doing %include and %resolve"),
|
||||
ztd::option('I', "no-include", false, "Don't resolve %include commands"),
|
||||
ztd::option('R', "no-resolve", false, "Don't resolve %resolve commands"),
|
||||
ztd::option("no-extend", false, "Don't add lxsh extension functions"),
|
||||
ztd::option("debashify", false, "Attempt to turn a bash-specific script into a POSIX shell script"),
|
||||
ztd::option("\r [var/fct processing]"),
|
||||
ztd::option("minify-var", false, "Minify variable names"),
|
||||
ztd::option("minify-fct", false, "Minify function names"),
|
||||
ztd::option("exclude-var", true, "List of matching regex to ignore for variable processing", "list"),
|
||||
ztd::option("exclude-fct", true, "List of matching regex to ignore for function processing", "list"),
|
||||
ztd::option("no-exclude-reserved",false, "Don't exclude reserved variables"),
|
||||
ztd::option("list-var", false, "List all variables set and invoked in the script"),
|
||||
ztd::option("list-var-def", false, "List all variables set in the script"),
|
||||
ztd::option("list-var-call", false, "List all variables invoked in the script"),
|
||||
ztd::option("list-fct", false, "List all functions defined in the script"),
|
||||
ztd::option("list-cmd", false, "List all commands invoked in the script"),
|
||||
ztd::option("remove-unused", false, "Remove unused functions and variables"),
|
||||
ztd::option("unset-var", false, "Add 'unset' to all vars at the start of the script to avoid environment interference")
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void get_opts()
|
||||
{
|
||||
g_cd=!options['C'].activated;
|
||||
|
|
@ -102,9 +100,8 @@ ztd::option_set create_resolve_opts()
|
|||
void print_help(const char* arg0)
|
||||
{
|
||||
printf("%s [options] <file> [arg...]\n", arg0);
|
||||
printf("Link extended shell\n");
|
||||
printf("Include files and resolve commands on build time\n");
|
||||
printf("See --help-commands for help on linker commands\n");
|
||||
printf("Extended shell linker\n");
|
||||
printf("Include files, resolve commands on build time, process and minify shell code\n");
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
options.print_help(4,25);
|
||||
|
|
|
|||
2285
src/parse.cpp
2285
src/parse.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,10 @@
|
|||
#include "util.hpp"
|
||||
#include "shellcode.hpp"
|
||||
#include "struc_helper.hpp"
|
||||
#include "options.hpp"
|
||||
#include "minify.hpp"
|
||||
|
||||
#include "errcodes.h"
|
||||
|
||||
// Global regex
|
||||
|
||||
|
|
@ -415,6 +419,67 @@ std::set<std::string> find_lxsh_commands(shmain* sh)
|
|||
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 **/
|
||||
|
||||
std::string quote_string(std::string const& in)
|
||||
|
|
@ -454,6 +519,7 @@ std::string boolstring(bool in)
|
|||
return "false";
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MODE
|
||||
std::string gen_json_struc(_obj* o)
|
||||
{
|
||||
if(o==nullptr)
|
||||
|
|
@ -781,3 +847,4 @@ std::string gen_json_struc(_obj* o)
|
|||
}
|
||||
return gen_json(vec);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ bool add_include(std::string const& file)
|
|||
if(it == truepath)
|
||||
return false;
|
||||
}
|
||||
// std::cout << truepath << std::endl;
|
||||
included.push_back(truepath);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -60,7 +59,7 @@ void _cd(std::string const& dir)
|
|||
// -- COMMANDS --
|
||||
|
||||
// return <name, contents>[]
|
||||
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, 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;
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
|||
std::vector<std::string> rargs;
|
||||
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)
|
||||
{
|
||||
|
|
@ -78,7 +77,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
|||
std::string dir;
|
||||
if(g_cd && !opts['C'])
|
||||
{
|
||||
dir=_pre_cd(filename);
|
||||
dir=_pre_cd(ctx.filename);
|
||||
if(ex_dir!=nullptr)
|
||||
*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;
|
||||
|
||||
|
|
@ -114,7 +113,7 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
|||
std::vector<std::string> rargs;
|
||||
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)
|
||||
{
|
||||
|
|
@ -124,7 +123,7 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
|||
std::string dir;
|
||||
if(g_cd && !opts['C'])
|
||||
{
|
||||
dir=_pre_cd(filename);
|
||||
dir=_pre_cd(ctx.filename);
|
||||
if(ex_dir!=nullptr)
|
||||
*ex_dir=dir;
|
||||
}
|
||||
|
|
@ -153,23 +152,33 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string co
|
|||
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::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
|
||||
ret.insert(ret.end(), sh->lst->cls.begin(), sh->lst->cls.end());
|
||||
// safety and cleanup
|
||||
sh->lst->cls.resize(0);
|
||||
delete sh;
|
||||
}
|
||||
shs.resize(0);
|
||||
// cd back
|
||||
_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
|
||||
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;
|
||||
|
||||
|
|
@ -186,10 +195,13 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
|||
{
|
||||
// get
|
||||
std::string dir;
|
||||
p=do_resolve_raw(cmd, filename, &dir);
|
||||
p=do_resolve_raw(cmd, ctx, &dir);
|
||||
|
||||
// do parse
|
||||
shmain* sh = parse_text(p.second);
|
||||
resolve(sh);
|
||||
parse_context newctx = make_context(ctx, p.second, '`'+p.first+'`');
|
||||
auto pp = parse_text(newctx);
|
||||
shmain* sh = pp.first;
|
||||
resolve(sh, pp.second);
|
||||
// get the cls
|
||||
ret = sh->lst->cls;
|
||||
// safety and cleanup
|
||||
|
|
@ -198,9 +210,9 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
|||
// cd back
|
||||
_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;
|
||||
|
|
@ -208,7 +220,7 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filena
|
|||
|
||||
// -- 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();
|
||||
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);
|
||||
|
||||
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")
|
||||
return std::make_pair(do_resolve_parse(in, filename), true);
|
||||
return std::make_pair(do_resolve_parse(in, ctx), true);
|
||||
else
|
||||
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;
|
||||
if(in == nullptr)
|
||||
|
|
@ -250,12 +262,12 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& fi
|
|||
std::string fulltext;
|
||||
if(g_include && strcmd == "%include")
|
||||
{
|
||||
for(auto it: do_include_raw(tc, filename) )
|
||||
for(auto it: do_include_raw(tc, ctx) )
|
||||
fulltext += it.second;
|
||||
}
|
||||
else if(g_resolve && strcmd == "%resolve")
|
||||
{
|
||||
fulltext = do_resolve_raw(tc, filename).second;
|
||||
fulltext = do_resolve_raw(tc, ctx).second;
|
||||
}
|
||||
else // skip
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void resolve(_obj* in, parse_context* ctx);
|
||||
// -- RECURSIVE CALL --
|
||||
|
||||
bool r_resolve(_obj* o, std::string* filename)
|
||||
bool r_resolve(_obj* o, parse_context* ct)
|
||||
{
|
||||
switch(o->type)
|
||||
{
|
||||
|
|
@ -337,7 +349,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
auto t = dynamic_cast<list*>(o);
|
||||
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)
|
||||
{
|
||||
// add new cls after current
|
||||
|
|
@ -350,7 +362,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
}
|
||||
else
|
||||
{
|
||||
resolve(t->cls[i], filename);
|
||||
resolve(t->cls[i], ct);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -360,7 +372,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
auto t = dynamic_cast<arglist*>(o);
|
||||
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)
|
||||
{
|
||||
// add new args
|
||||
|
|
@ -372,7 +384,7 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
}
|
||||
else
|
||||
{
|
||||
resolve(t->args[i], filename);
|
||||
resolve(t->args[i], ct);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -382,12 +394,12 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
auto t = dynamic_cast<cmd*>(o);
|
||||
for(auto it: t->var_assigns) // var assigns
|
||||
{
|
||||
resolve_arg(it.second, *filename, true); // force quoted
|
||||
resolve(it.second, filename);
|
||||
resolve_arg(it.second, *ct, true); // force quoted
|
||||
resolve(it.second, ct);
|
||||
}
|
||||
for(auto it: t->redirs)
|
||||
resolve(it, filename);
|
||||
resolve(t->args, filename);
|
||||
resolve(it, ct);
|
||||
resolve(t->args, ct);
|
||||
return false;
|
||||
}; break;
|
||||
case _obj::block_case :
|
||||
|
|
@ -395,15 +407,15 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
auto t = dynamic_cast<case_block*>(o);
|
||||
for(auto sc: t->cases)
|
||||
{
|
||||
resolve_arg(t->carg, *filename, true); // force quoted
|
||||
resolve(t->carg, filename);
|
||||
resolve_arg(t->carg, *ct, true); // force quoted
|
||||
resolve(t->carg, ct);
|
||||
|
||||
for(auto it: sc.first)
|
||||
{
|
||||
resolve_arg(it, *filename, true); // force quoted
|
||||
resolve(it, filename);
|
||||
resolve_arg(it, *ct, true); // force quoted
|
||||
resolve(it, ct);
|
||||
}
|
||||
resolve(sc.second, filename);
|
||||
resolve(sc.second, ct);
|
||||
}
|
||||
}; break;
|
||||
default: break;
|
||||
|
|
@ -412,12 +424,13 @@ bool r_resolve(_obj* o, std::string* filename)
|
|||
}
|
||||
|
||||
// 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 "struc_helper.hpp"
|
||||
|
||||
const std::map<const std::string, const struct lxsh_fct> lxsh_extend_fcts = {
|
||||
{ "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(k*8). Default 2", RANDOM_SH} },
|
||||
{ "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} },
|
||||
{ "_lxsh_random_tmpfile", { "[N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} } }
|
||||
const std::map<const std::string, const lxsh_fct> lxsh_extend_fcts = {
|
||||
{ "_lxsh_random", { "[K]", "Generate a random number between 0 and 2^(K*8). Default 2", RANDOM_SH} },
|
||||
{ "_lxsh_random_string", { "[N]", "Generate a random alphanumeric string of length N. Default 20", RANDOM_STRING_SH} },
|
||||
{ "_lxsh_random_tmpfile", { "[N]", "Get a random TMP filepath, with N random chars. Default 20", RANDOM_TMPFILE_SH, {"_lxsh_random_string"} }
|
||||
}
|
||||
};
|
||||
|
||||
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_get", { "<ARRAY> <I>", "Get value from array", ARRAY_GET_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} }
|
||||
};
|
||||
|
||||
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;
|
||||
for(auto it: lxsh_extend_fcts)
|
||||
|
|
@ -27,7 +28,7 @@ std::map<const std::string, const struct lxsh_fct> create_allfcts()
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
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)
|
||||
|
|
@ -34,7 +34,7 @@ cmd* make_cmd(std::vector<arg*> const& args)
|
|||
|
||||
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)
|
||||
|
|
@ -48,22 +48,23 @@ pipeline* make_pipeline(std::vector<block*> const& bls)
|
|||
|
||||
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)
|
||||
{
|
||||
return parse_condlist(in.c_str(), in.size(), 0).first;
|
||||
return parse_condlist(make_context(in)).first;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
std::string str = in->generate(0);
|
||||
return parse_arg(str.c_str(), str.size(), 0).first;
|
||||
return parse_arg(make_context(str)).first;
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
|
@ -147,20 +148,47 @@ size_t cmd::arglist_size()
|
|||
|
||||
// string getters
|
||||
|
||||
bool arg::is_string()
|
||||
{
|
||||
return sa.size() == 1 && sa[0]->type == _obj::subarg_string;
|
||||
}
|
||||
|
||||
std::string arg::string()
|
||||
{
|
||||
if(sa.size() != 1 || sa[0]->type != subarg::subarg_string)
|
||||
if(!this->is_string())
|
||||
return "";
|
||||
return dynamic_cast<string_subarg*>(sa[0])->val;
|
||||
}
|
||||
|
||||
std::string arg::first_sa_string()
|
||||
{
|
||||
if(sa.size() <=0 || sa[0]->type != subarg::subarg_string)
|
||||
return "";
|
||||
if(sa.size() <=0 || sa[0]->type != _obj::subarg_string)
|
||||
return "";
|
||||
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> ret;
|
||||
|
|
|
|||
85
src/util.cpp
85
src/util.cpp
|
|
@ -7,8 +7,10 @@
|
|||
#include <tuple>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <ztd/shell.hpp>
|
||||
#include <ztd/color.hpp>
|
||||
|
||||
std::string indenting_string="\t";
|
||||
|
||||
|
|
@ -210,16 +212,15 @@ std::string repeatString(std::string const& str, uint32_t n)
|
|||
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)
|
||||
{
|
||||
int i=0, j=0; // j: last newline
|
||||
int line=1; //n: line #
|
||||
int in_size=strlen(in);
|
||||
uint64_t index = e.where();
|
||||
|
||||
uint64_t i=0, j=0; // j: last newline
|
||||
uint64_t line=1; //n: line #
|
||||
uint64_t in_size=strlen(in);
|
||||
if(index >= 0)
|
||||
{
|
||||
while(i < in_size && i < index)
|
||||
|
|
@ -232,59 +233,25 @@ void printErrorIndex(const char* in, const int index, const std::string& message
|
|||
i++;
|
||||
}
|
||||
while(i < in_size && in[i]!='\n')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(origin != "")
|
||||
std::cerr << ztd::color::b_white;
|
||||
fprintf(stderr, "%s:%lu:%lu: ", e.origin(), line, index-j+1);
|
||||
|
||||
ztd::color level_color;
|
||||
const std::string& level = e.level();
|
||||
if(level == "error")
|
||||
level_color = ztd::color::b_red;
|
||||
else if(level == "warning")
|
||||
level_color = ztd::color::b_magenta;
|
||||
else if(level == "info")
|
||||
level_color = ztd::color::b_cyan;
|
||||
|
||||
std::cerr << level_color << e.level() << ztd::color::none;
|
||||
fprintf(stderr, ": %s\n", e.what());
|
||||
if(print_line)
|
||||
{
|
||||
fprintf(stderr, "%s:%u:%u: %s\n", origin.c_str(), line, index-j+1, message.c_str());
|
||||
if(print_line)
|
||||
{
|
||||
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||
}
|
||||
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int execute(shmain* sh, std::vector<std::string>& args)
|
||||
{
|
||||
std::string data=sh->generate();
|
||||
|
||||
std::string filename = basename(args[0]);
|
||||
|
||||
// generate path
|
||||
std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ;
|
||||
std::string dirpath = tmpdir + "/lxsh_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10");
|
||||
std::string filepath = dirpath+'/'+filename;
|
||||
|
||||
// create dir
|
||||
if(ztd::exec("mkdir", "-p", dirpath).second)
|
||||
{
|
||||
throw std::runtime_error("Failed to create directory '"+dirpath+'\'');
|
||||
}
|
||||
|
||||
// create stream
|
||||
std::ofstream stream(filepath);
|
||||
if(!stream)
|
||||
{
|
||||
ztd::exec("rm", "-rf", dirpath);
|
||||
throw std::runtime_error("Failed to write to '"+filepath+'\'');
|
||||
}
|
||||
|
||||
// output
|
||||
stream << data;
|
||||
stream.close();
|
||||
if(ztd::exec("chmod", "+x", filepath).second != 0)
|
||||
{
|
||||
ztd::exec("rm", "-rf", dirpath);
|
||||
throw std::runtime_error("Failed to make '"+filepath+"' executable");
|
||||
}
|
||||
|
||||
// exec
|
||||
int retval=_exec(filepath, args);
|
||||
ztd::exec("rm", "-rf", dirpath);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue