implement associative array debashifying + shellcode building process

This commit is contained in:
zawz 2021-02-26 15:18:17 +01:00
parent fd4c1b0d05
commit 931590a334
18 changed files with 261 additions and 76 deletions

2
.gitignore vendored
View file

@ -7,4 +7,4 @@
/gmon.out /gmon.out
/profiling/* /profiling/*
/profiling.* /profiling.*
/include/g_version.h /include/g_*.h

View file

@ -39,11 +39,12 @@ endif
## END CONFIG ## ## END CONFIG ##
$(shell ./generate_version.sh) $(shell ./generate_version.sh)
$(shell ./generate_shellcode.sh)
$(shell mkdir -p $(ODIR)) $(shell mkdir -p $(ODIR))
$(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') DEPS = $(shell find $(IDIR) -type f -regex '.*\.hp?p?' ! -name 'g_version.h' ! -name 'g_shellcode.h')
# 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)/|$(ODIR)/|g')
@ -58,6 +59,9 @@ $(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(ODIR)/main.o: $(SRCDIR)/main.cpp $(DEPS) $(IDIR)/g_version.h $(ODIR)/main.o: $(SRCDIR)/main.cpp $(DEPS) $(IDIR)/g_version.h
$(CC) $(CXXFLAGS) -c -o $@ $< $(CC) $(CXXFLAGS) -c -o $@ $<
$(ODIR)/debashify.o: $(SRCDIR)/debashify.cpp $(DEPS) $(IDIR)/g_shellcode.h
$(CC) $(CXXFLAGS) -c -o $@ $<
lxsh: $(OBJ) lxsh: $(OBJ)
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

34
generate_shellcode.sh Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
file=include/g_shellcode.h
tmpfile=${TMPDIR-/tmp}/lxsh_shellcodegen
codedir=shellcode
# $1 = file
minimize() {
if which lxsh >/dev/null 2>&1 ; then
lxsh -m "$1"
elif which shfmt >/dev/null 2>&1 ; then
shfmt -mn "$1"
else
cat "$1"
fi
}
to_cstr() {
sed 's|\\|\\\\|g;s|\"|\\\"|g' | sed ':a;N;$!ba;s/\n/\\n/g;'
}
echo '#ifndef G_VERSION_H' > "$tmpfile"
echo '#define G_VERSION_H' >> "$tmpfile"
for I in "$codedir"/*.sh
do
printf '#define %s "%s"\n' "$(basename "$I" | tr [:lower:] [:upper:] | tr '.' '_')" "$(minimize "$I" | to_cstr)" >> "$tmpfile"
done
echo "#endif" >> "$tmpfile"
if [ "$(md5sum "$tmpfile" | cut -d' ' -f1)" != "$(md5sum "$file" | cut -d' ' -f1)" ] ; then
mv "$tmpfile" "$file"
else
rm "$tmpfile"
fi

View file

@ -308,7 +308,7 @@ public:
static const std::string empty_string; static const std::string empty_string;
std::string const& firstarg_string(); std::string const& arg_string(uint32_t n);
size_t arglist_size(); size_t arglist_size();

View file

@ -16,6 +16,8 @@ pipeline* make_pipeline(std::string const& in);
condlist* make_condlist(std::string const& in); condlist* make_condlist(std::string const& in);
list* make_list(std::string const& in); list* make_list(std::string const& in);
block* make_block(std::string const& in);
// copy // copy
arg* copy(arg* in); arg* copy(arg* in);
variable* copy(variable* in); variable* copy(variable* in);

View file

@ -0,0 +1,7 @@
__lxsh_array_create() {
printf "%s" "$1"
shift 1
for N ; do
printf "\t%s" "$N"
done
}

7
shellcode/array_get.sh Normal file
View file

@ -0,0 +1,7 @@
__lxsh_array_get() {
if [ "$2" = "*" ] || [ "$2" = "@" ] ; then
printf "%s" "$1" | tr '\t' ' '
else
printf "%s" "$1" | cut -f$(($2+1))
fi
}

6
shellcode/array_set.sh Normal file
View file

@ -0,0 +1,6 @@
__lxsh_array_set()
{
[ "$2" -gt 0 ] && printf "%s\t" "$(printf "%s" "$1" | cut -f1-$2)"
printf "%s" "$3"
[ "$2" -lt $(printf "%s" "$1" | tr -dc '\t' | wc -c) ] && { printf "\t" ; printf "%s" "$1"|cut -f$(($2+2))-; }
}

6
shellcode/map_create.sh Normal file
View file

@ -0,0 +1,6 @@
__lxsh_map_create() {
for I
do
printf "%s]%s\n" "$(echo "$I" | cut -d']' -f1 | cut -d '[' -f2)" "$(echo "$I" | cut -d '=' -f2-)"
done
}

7
shellcode/map_get.sh Normal file
View file

@ -0,0 +1,7 @@
__lxsh_map_get() {
if [ "$2" = \* ] || [ "$2" = @ ] ; then
printf "%s\n" "$1" | sort | cut -d ']' -f2-
else
printf "%s\n" "$1" | grep "^$2\]" | cut -d ']' -f2-
fi
}

6
shellcode/map_set.sh Normal file
View file

@ -0,0 +1,6 @@
__lxsh_map_set() {
printf "%s\n" "$1" | grep -v "^$2\]"
if [ -n "$3" ] ; then
printf "%s]%s\n" "$2" "$3"
fi
}

View file

@ -0,0 +1,3 @@
__lxsh_random_string() {
env LC_CTYPE=C tr -dc 'a-zA-Z0-9' </dev/urandom | head -c "${1-20}"
}

View file

@ -0,0 +1,3 @@
__lxsh_random_tmpfile() {
echo "${TMPDIR-/tmp}/$1$(__lxsh_random_string 20)"
}

View file

@ -6,6 +6,8 @@
#include "parse.hpp" #include "parse.hpp"
#include "struc_helper.hpp" #include "struc_helper.hpp"
#include "g_shellcode.h"
typedef struct debashify_params { typedef struct debashify_params {
bool need_random_string=false; bool need_random_string=false;
@ -13,7 +15,12 @@ typedef struct debashify_params {
bool need_array_create=false; bool need_array_create=false;
bool need_array_set=false; bool need_array_set=false;
bool need_array_get=false; bool need_array_get=false;
std::vector<std::string> debashed_arrays; bool need_map_create=false;
bool need_map_set=false;
bool need_map_get=false;
// map of detected arrays
// bool value: is associative
std::map<std::string,bool> arrays;
} debashify_params; } debashify_params;
@ -99,7 +106,7 @@ bool debashify_bashtest(pipeline* pl)
return false; return false;
cmd* in = dynamic_cast<cmd*>(pl->cmds[0]); cmd* in = dynamic_cast<cmd*>(pl->cmds[0]);
if(in->firstarg_string() == "[[") if(in->arg_string(0) == "[[")
{ {
brace* br = new brace(new list); brace* br = new brace(new list);
condlist* cl = new condlist; condlist* cl = new condlist;
@ -134,27 +141,80 @@ bool debashify_bashtest(pipeline* pl)
return false; return false;
} }
bool debashify_declare(cmd* in) void warn(std::string const& in)
{ {
std::string cmd=in->firstarg_string(); std::cerr << "WARN: " << in << std::endl;
if(cmd == "declare" || cmd == "typeset" || cmd == "readonly")
throw std::runtime_error(strf("Cannot debashify '%s'", cmd.c_str()));
return false;
} }
cmd* make_array_get_cmd(std::string const& varname, arg* index) std::string get_declare_opt(cmd* in)
{
if(in->var_assigns[0].second!=nullptr)
{
return in->var_assigns[0].second->string();
}
return "";
}
bool debashify_declare(list* in, debashify_params* params)
{
bool has_found=false;
for(uint32_t i=0; i<in->cls.size(); i++)
{
// not a cmd: go to next
if(in->cls[i]->pls[0]->cmds[0]->type != _obj::block_cmd)
continue;
cmd* c1 = dynamic_cast<cmd*>(in->cls[i]->pls[0]->cmds[0]);
std::string const& cmdstr=c1->arg_string(0);
if(cmdstr == "declare" || cmdstr == "typeset" || cmdstr == "readonly")
{
if(cmdstr == "readonly")
{
warn("removing 'readonly'");
}
else
{
std::string const& op = get_declare_opt(c1);
if(op == "-a")
{
for(auto it: c1->var_assigns)
{
if(it.first != nullptr)
params->arrays[it.first->varname] = false;
}
}
else if(op == "-A")
{
for(auto it: c1->var_assigns)
{
if(it.first != nullptr)
params->arrays[it.first->varname] = true;
}
}
else
warn( strf("removing '%s' with argument '%s'", cmdstr.c_str(), op.c_str()) );
}
has_found=true;
delete in->cls[i];
in->cls.erase(in->cls.begin()+i);
}
}
return has_found;
}
cmd* make_cmd_varindex(std::string const& strcmd, std::string const& varname, arg* index)
{ {
cmd* c = new cmd(new arglist); cmd* c = new cmd(new arglist);
// __lxsh_array_get // cmd
c->args->add( new arg("__lxsh_array_get") ); c->args->add( new arg(strcmd) );
// __lxsh_array_get "$VAR" // cmd "$VAR"
c->args->add( make_arg("\"$"+varname+"\"") ); c->args->add( make_arg("\"$"+varname+"\"") );
// __lxsh_array_get "$VAR" N // cmd "$VAR" N
c->args->add( index ); c->args->add( index );
return c; return c;
} }
subshell_arithmetic* do_debashify_arithmetic(arithmetic* in) subshell_arithmetic* do_debashify_arithmetic(arithmetic* in, debashify_params* params)
{ {
subshell_arithmetic* ret = nullptr; subshell_arithmetic* ret = nullptr;
if(in->type == _obj::arithmetic_variable) if(in->type == _obj::arithmetic_variable)
@ -169,7 +229,18 @@ subshell_arithmetic* do_debashify_arithmetic(arithmetic* in)
arg* index = t->var->index; arg* index = t->var->index;
t->var->index=nullptr; t->var->index=nullptr;
cmd* c = make_array_get_cmd(varname, index); cmd* c;
if(params->arrays[varname])
{
c = make_cmd_varindex("__lxsh_map_get", varname, index);
params->need_map_get=true;
}
else
{
c = make_cmd_varindex("__lxsh_array_get", varname, index);
params->need_array_get=true;
}
ret = new subshell_arithmetic(new subshell(c)); ret = new subshell_arithmetic(new subshell(c));
} }
} }
@ -183,7 +254,7 @@ bool debashify_array_arithmetic(_obj* o, debashify_params* params)
{ {
case _obj::subarg_arithmetic: { case _obj::subarg_arithmetic: {
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o); arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
arithmetic* r = do_debashify_arithmetic(t->arith); arithmetic* r = do_debashify_arithmetic(t->arith, params);
if(r!=nullptr) if(r!=nullptr)
{ {
ret=true; ret=true;
@ -193,14 +264,14 @@ bool debashify_array_arithmetic(_obj* o, debashify_params* params)
} break; } break;
case _obj::arithmetic_operation: { case _obj::arithmetic_operation: {
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o); operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
arithmetic* r = do_debashify_arithmetic(t->val1); arithmetic* r = do_debashify_arithmetic(t->val1, params);
if(r!=nullptr) if(r!=nullptr)
{ {
ret=true; ret=true;
delete t->val1; delete t->val1;
t->val1 = r; t->val1 = r;
} }
r = do_debashify_arithmetic(t->val2); r = do_debashify_arithmetic(t->val2, params);
if(r!=nullptr) if(r!=nullptr)
{ {
ret=true; ret=true;
@ -210,7 +281,7 @@ bool debashify_array_arithmetic(_obj* o, debashify_params* params)
} break; } break;
case _obj::arithmetic_parenthesis: { case _obj::arithmetic_parenthesis: {
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o); parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
arithmetic* r = do_debashify_arithmetic(t->val); arithmetic* r = do_debashify_arithmetic(t->val, params);
if(r!=nullptr) if(r!=nullptr)
{ {
ret=true; ret=true;
@ -237,7 +308,6 @@ bool debashify_array_get(arg* in, debashify_params* params)
if(t->var->manip != nullptr) if(t->var->manip != nullptr)
throw std::runtime_error("Cannot debashify manipulations on ${VAR[]}"); throw std::runtime_error("Cannot debashify manipulations on ${VAR[]}");
params->need_array_get = true;
std::string varname = t->var->varname; std::string varname = t->var->varname;
arg* index = t->var->index; arg* index = t->var->index;
t->var->index=nullptr; t->var->index=nullptr;
@ -248,7 +318,18 @@ bool debashify_array_get(arg* in, debashify_params* params)
index = new arg("\\*"); index = new arg("\\*");
} }
cmd* c = make_array_get_cmd(varname, index); cmd* c;
if(params->arrays[varname])
{
c = make_cmd_varindex("__lxsh_map_get", varname, index);
params->need_map_get=true;
}
else
{
c = make_cmd_varindex("__lxsh_array_get", varname, index);
params->need_array_get=true;
}
subshell_subarg* sb = new subshell_subarg(new subshell(c)); subshell_subarg* sb = new subshell_subarg(new subshell(c));
sb->quoted=quoted; sb->quoted=quoted;
delete *it; delete *it;
@ -265,19 +346,28 @@ bool debashify_array_set(cmd* in, debashify_params* params)
bool has_replaced=false; bool has_replaced=false;
for(auto it = in->var_assigns.begin() ; it != in->var_assigns.end() ; it++) for(auto it = in->var_assigns.begin() ; it != in->var_assigns.end() ; it++)
{ {
if(it->second != nullptr && it->second->size()>0 && it->second->first_sa_string().substr(0,2) == "=(") if(it->first!=nullptr && it->second != nullptr && it->second->size()>0 && it->second->first_sa_string().substr(0,2) == "=(")
{ {
// array creation: VAR=() // array creation: VAR=()
params->need_array_create=true;
// extract arguments from =(ARGS...) // extract arguments from =(ARGS...)
std::string gen=it->second->generate(0); std::string gen=it->second->generate(0);
std::string varname=it->first->varname;
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( gen.c_str(), gen.size(), 0 ).first;
cmd* c = new cmd(args); cmd* c = new cmd(args);
// cmd first argument is __lxsh_array_create // cmd first argument is __lxsh_X_create
c->args->insert(0, new arg("__lxsh_array_create") ); if(params->arrays[varname])
{
c->args->insert(0, new arg("__lxsh_map_create") );
params->need_map_create=true;
}
else
{
c->args->insert(0, new arg("__lxsh_array_create") );
params->need_array_create=true;
}
subshell_subarg* sb = new subshell_subarg(new subshell(c)); subshell_subarg* sb = new subshell_subarg(new subshell(c));
// insert new value // insert new value
delete it->second; delete it->second;
@ -303,19 +393,40 @@ bool debashify_array_set(cmd* in, debashify_params* params)
if(tt->val.substr(0,2) == "+=") if(tt->val.substr(0,2) == "+=")
{ {
tt->val = tt->val.substr(2); // remove += tt->val = tt->val.substr(2); // remove +=
// create array get of value // create array get of value
cmd* c = make_array_get_cmd(varname, copy(index)); cmd* c;
if(params->arrays[varname])
{
c = make_cmd_varindex("__lxsh_map_get", varname, copy(index));
params->need_map_get=true;
}
else
{
c = make_cmd_varindex("__lxsh_array_get", varname, copy(index));
params->need_array_get=true;
}
subshell_subarg* sb = new subshell_subarg(new subshell(c)); subshell_subarg* sb = new subshell_subarg(new subshell(c));
sb->quoted=true; sb->quoted=true;
value->insert(0, "\""); value->insert(0, "\"");
value->insert(0, sb); value->insert(0, sb);
value->insert(0, "\""); value->insert(0, "\"");
} }
else else
tt->val = tt->val.substr(1); // remove = tt->val = tt->val.substr(1); // remove =
cmd* c = new cmd(new arglist); cmd* c = new cmd(new arglist);
c->args->add( new arg("__lxsh_array_set") ); if(params->arrays[varname])
{
c->args->add(new arg("__lxsh_map_set") );
params->need_map_set=true;
}
else
{
c->args->add(new arg("__lxsh_array_set") );
params->need_array_set=true;
}
// __lxsh_array_set "$VAR" // __lxsh_array_set "$VAR"
c->args->add( make_arg("\"$"+varname+"\"") ); c->args->add( make_arg("\"$"+varname+"\"") );
// __lxsh_array_set "$VAR" N // __lxsh_array_set "$VAR" N
@ -345,7 +456,16 @@ bool debashify_array_set(cmd* in, debashify_params* params)
arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).first; arglist* args = parse_arglist( gen.c_str(), gen.size(), 0 ).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
c->args->insert(0, new arg("__lxsh_array_create") ); if(params->arrays[varname])
{
throw std::runtime_error("Cannot debashify VAR+=() on associative arrays");
}
else
{
c->args->insert(0, new arg("__lxsh_array_create") );
params->need_array_create=true;
}
// second arg is varname
c->args->insert(1, make_arg("\"$"+varname+"\"") ); c->args->insert(1, make_arg("\"$"+varname+"\"") );
subshell_subarg* sb = new subshell_subarg(new subshell(c)); subshell_subarg* sb = new subshell_subarg(new subshell(c));
// insert new value // insert new value
@ -523,38 +643,6 @@ bool debashify_procsub(list* lst, debashify_params* params)
return has_replaced; return has_replaced;
} }
// create the random string generator function
//
block* create_random_string_func()
{
std::string code="__lxsh_random_string() { env LC_CTYPE=C tr -dc 'a-zA-Z0-9' </dev/urandom | head -c ${1-20}; }";
return parse_block(code.c_str(), code.size(), 0).first;
}
block* create_random_tmpfile_func()
{
std::string code="__lxsh_random_tmpfile() { echo \"${TMPDIR-/tmp}/$1$(__lxsh_random_string 20)\"; }";
return parse_block(code.c_str(), code.size(), 0).first;
}
block* create_array_set_func()
{
std::string code="__lxsh_array_set()\n{\n {\n printf \"%s\\n%s\" \"$3\" \"$1\"\n printf '%*s' \"$(($2+1))\" | tr ' ' \"\\n\"\n } | awk 'BEGIN{RS=\"\\n\"};{if(NR==1){ val=$0 } else if(NR=='\"$(($2+2))\"'){ printf \"%s%s\",val,RS } else { printf \"%s%s\",$0,RS } }'\n}";
return parse_block(code.c_str(), code.size(), 0).first;
}
block* create_array_create_func()
{
std::string code="__lxsh_array_create() {\n for N ; do\n echo \"$N\"\n done\n}";
return parse_block(code.c_str(), code.size(), 0).first;
}
block* create_array_get_func()
{
std::string code="__lxsh_array_get() {\n if [ \"$2\" = \"*\" ] || [ \"$2\" = \"@\" ] ; then\n printf \"%s\" \"$1\" | tr '\\n' ' '\n else\n echo \"$1\" | awk 'BEGIN{RS=\"\\n\"};{if(NR=='\"$(($2+1))\"'){ print } }'\n fi\n}";
return parse_block(code.c_str(), code.size(), 0).first;
}
bool r_debashify(_obj* o, debashify_params* params) bool r_debashify(_obj* o, debashify_params* params)
{ {
// global debashifies // global debashifies
@ -567,6 +655,7 @@ bool r_debashify(_obj* o, debashify_params* params)
} break; } break;
case _obj::_list: { case _obj::_list: {
list* t = dynamic_cast<list*>(o); list* t = dynamic_cast<list*>(o);
debashify_declare(t, params);
debashify_procsub(t, params); debashify_procsub(t, params);
} break; } break;
case _obj::_pipeline: { case _obj::_pipeline: {
@ -577,7 +666,6 @@ bool r_debashify(_obj* o, debashify_params* params)
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(o); cmd* t = dynamic_cast<cmd*>(o);
debashify_combined_redirects(t); debashify_combined_redirects(t);
debashify_declare(t);
debashify_array_set(t, params); debashify_array_set(t, params);
debashify_plusequal(t, params); debashify_plusequal(t, params);
} break; } break;
@ -624,13 +712,19 @@ void debashify(shmain* sh)
sh->shebang = "#!/bin/sh"; sh->shebang = "#!/bin/sh";
recurse(r_debashify, sh, &params); recurse(r_debashify, sh, &params);
if(params.need_random_string || params.need_random_tmpfile) if(params.need_random_string || params.need_random_tmpfile)
sh->lst->insert(0, new condlist(create_random_tmpfile_func())); sh->lst->insert(0, new condlist(make_block(RANDOM_TMPFILE_SH)));
if(params.need_random_tmpfile) if(params.need_random_tmpfile)
sh->lst->insert(0, new condlist(create_random_string_func())); sh->lst->insert(0, new condlist(make_block(RANDOM_STRING_SH)));
if(params.need_array_create) if(params.need_array_create)
sh->lst->insert(0, new condlist(create_array_create_func())); sh->lst->insert(0, new condlist(make_block(ARRAY_CREATE_SH)));
if(params.need_array_set) if(params.need_array_set)
sh->lst->insert(0, new condlist(create_array_set_func())); sh->lst->insert(0, new condlist(make_block(ARRAY_SET_SH)));
if(params.need_array_get) if(params.need_array_get)
sh->lst->insert(0, new condlist(create_array_get_func())); sh->lst->insert(0, new condlist(make_block(ARRAY_GET_SH)));
if(params.need_map_create)
sh->lst->insert(0, new condlist(make_block(MAP_CREATE_SH)));
if(params.need_map_set)
sh->lst->insert(0, new condlist(make_block(MAP_SET_SH)));
if(params.need_map_get)
sh->lst->insert(0, new condlist(make_block(MAP_GET_SH)));
} }

View file

@ -39,7 +39,7 @@ bool r_replace_fct(_obj* in, strmap_t* fctmap)
}; break; }; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->firstarg_string(); std::string cmdname = t->arg_string(0);
auto el=fctmap->find(cmdname); auto el=fctmap->find(cmdname);
if(el!=fctmap->end()) if(el!=fctmap->end())
{ {

View file

@ -164,7 +164,7 @@ bool cmd::is_argvar()
bool cmd::is(std::string const& in) bool cmd::is(std::string const& in)
{ {
return in == this->firstarg_string(); return in == this->arg_string(0);
} }
/** GETTERS **/ /** GETTERS **/
@ -303,7 +303,7 @@ bool r_get_cmd(_obj* in, countmap_t* all_cmds)
{ {
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd* t = dynamic_cast<cmd*>(in);
std::string cmdname = t->firstarg_string(); std::string cmdname = t->arg_string(0);
if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second) if(cmdname != "" && !all_cmds->insert( std::make_pair(cmdname, 1) ).second)
(*all_cmds)[cmdname]++; (*all_cmds)[cmdname]++;
}; break; }; break;

View file

@ -213,7 +213,7 @@ std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, shmain
if(tc == nullptr) if(tc == nullptr)
return std::make_pair(std::vector<condlist*>(), false); return std::make_pair(std::vector<condlist*>(), false);
std::string const& strcmd=tc->firstarg_string(); 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, parent), true); return std::make_pair(do_include_parse(in, parent), true);
@ -245,7 +245,7 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, shmain* parent, bool
cmd* c = tc->first_cmd(); cmd* c = tc->first_cmd();
if(c == nullptr) // skip if not cmd if(c == nullptr) // skip if not cmd
continue; continue;
std::string strcmd=c->firstarg_string(); std::string strcmd=c->arg_string(0);
std::string fulltext; std::string fulltext;
if(g_include && strcmd == "%include") if(g_include && strcmd == "%include")
{ {

View file

@ -61,6 +61,12 @@ list* make_list(std::string const& in)
return parse_list_until(in.c_str(), in.size(), 0, 0).first; return parse_list_until(in.c_str(), in.size(), 0, 0).first;
} }
block* make_block(std::string const& in)
{
return parse_block(in.c_str(), in.size(), 0).first;
}
// copy // copy
arg* copy(arg* in) { arg* copy(arg* in) {
@ -152,10 +158,10 @@ std::vector<std::string> arglist::strargs(uint32_t start)
return ret; return ret;
} }
std::string const& cmd::firstarg_string() std::string const& cmd::arg_string(uint32_t n)
{ {
if(args!=nullptr && args->args.size()>0 && args->args[0]->sa.size() == 1 && args->args[0]->sa[0]->type == _obj::subarg_string) if(args!=nullptr && args->args.size()>n && args->args[n]->sa.size() == 1 && args->args[n]->sa[0]->type == _obj::subarg_string)
return dynamic_cast<string_subarg*>(args->args[0]->sa[0])->val; return dynamic_cast<string_subarg*>(args->args[n]->sa[0])->val;
return cmd::empty_string; return cmd::empty_string;
} }