[Quests] Cleanup Quest Parser Logic (#4025)

* [Quests] Cleanup Quest Parser Logic

# Notes
- Consolidate duplicated code into loops to make it easier to read and easier to add on to.

# Images

* Update quest_parser_collection.cpp

* Push

* Push

* Update embperl.cpp

* Push

* Additional cleanup, use File::Exists utility

* Range based loops

* Update embparser.cpp

* Cleanup

* Update embparser.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Alex King
2024-02-05 19:53:16 -05:00
committed by GitHub
parent 9e2afd5571
commit 331e04fbf8
7 changed files with 2472 additions and 2109 deletions
+88 -97
View File
@@ -27,16 +27,18 @@ Eglin
XS(XS_EQEmuIO_PRINT);
#endif //EMBPERL_IO_CAPTURE
const char *argv_eqemu[] = { "",
const char* argv_eqemu[] = {
"",
#ifdef EMBPERL_IO_CAPTURE
"-w", "-W",
"-w", "-W",
#endif
"-e", "0;", nullptr };
"-e", "0;", nullptr
};
#ifdef EMBPERL_IO_CAPTURE
int argc = 5;
int argc = 5;
#else
int argc = 3;
int argc = 3;
#endif
//so embedded scripts can use xs extensions (ala 'use socket;')
EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
@@ -46,7 +48,7 @@ EXTERN_C void xs_init(pTHX)
strncpy(file, __FILE__, 256);
file[255] = '\0';
char buf[128]; //shouldent have any function names longer than this.
char buf[128]; //shouldent have any function names longer than this.
//add the strcpy stuff to get rid of const warnings....
@@ -58,20 +60,20 @@ EXTERN_C void xs_init(pTHX)
Embperl::Embperl()
{
char **argv = (char **)argv_eqemu;
char **env = { nullptr };
in_use = true; //in case one of these files generates an event
char** argv = (char**) argv_eqemu;
char** env = { nullptr };
PERL_SYS_INIT3(&argc, &argv, &env);
DoInit();
}
void Embperl::DoInit() {
char **argv = (char **)argv_eqemu;
char **env = { nullptr };
void Embperl::DoInit()
{
char** argv = (char**) argv_eqemu;
my_perl = perl_alloc();
//setup perl...
if(!my_perl)
if (!my_perl) {
throw "Failed to init Perl (perl_alloc)";
}
PERL_SET_CONTEXT(my_perl);
PERL_SET_INTERP(my_perl);
PL_perl_destruct_level = 1;
@@ -80,17 +82,17 @@ void Embperl::DoInit() {
perl_run(my_perl);
//a little routine we use a lot.
eval_pv("sub my_eval { eval $_[0];}", TRUE); //dies on error
eval_pv("sub my_eval { eval $_[0];}", TRUE); //dies on error
//ruin the perl exit and command:
eval_pv("sub my_exit {}",TRUE);
eval_pv("sub my_sleep {}",TRUE);
if(gv_stashpv("CORE::GLOBAL", FALSE)) {
GV *exitgp = gv_fetchpv("CORE::GLOBAL::exit", TRUE, SVt_PVCV);
GvCV_set(exitgp, perl_get_cv("my_exit", TRUE)); //dies on error
eval_pv("sub my_exit {}", TRUE);
eval_pv("sub my_sleep {}", TRUE);
if (gv_stashpv("CORE::GLOBAL", FALSE)) {
GV* exitgp = gv_fetchpv("CORE::GLOBAL::exit", TRUE, SVt_PVCV);
GvCV_set(exitgp, perl_get_cv("my_exit", TRUE)); //dies on error
GvIMPORTED_CV_on(exitgp);
GV *sleepgp = gv_fetchpv("CORE::GLOBAL::sleep", TRUE, SVt_PVCV);
GvCV_set(sleepgp, perl_get_cv("my_sleep", TRUE)); //dies on error
GV* sleepgp = gv_fetchpv("CORE::GLOBAL::sleep", TRUE, SVt_PVCV);
GvCV_set(sleepgp, perl_get_cv("my_sleep", TRUE)); //dies on error
GvIMPORTED_CV_on(sleepgp);
}
@@ -98,8 +100,7 @@ void Embperl::DoInit() {
try {
init_eval_file();
}
catch(std::string& e)
{
catch (std::string& e) {
//remember... lasterr() is no good if we crap out here, in construction
LogQuests("Perl Error [{}]", e);
throw "failed to install eval_file hook";
@@ -110,69 +111,62 @@ void Embperl::DoInit() {
//make a tieable class to capture IO and pass it into EQEMuLog
eval_pv(
"package EQEmuIO; "
"sub TIEHANDLE { my $me = bless {}, $_[0]; $me->PRINT('Creating '. $me); return($me); } "
"sub WRITE { } "
//dunno why I need to shift off fmt here, but it dosent like without it
"sub PRINTF { my $me = shift; my $fmt = shift; $me->PRINT(sprintf($fmt, @_)); } "
"sub CLOSE { my $me = shift; $me->PRINT('Closing '.$me); } "
"sub DESTROY { my $me = shift; $me->PRINT('Destroying '.$me); } "
//this ties us for all packages, just do it in quest since thats kinda 'our' package
"package quest;"
" if(tied *STDOUT) { untie(*STDOUT); }"
" if(tied *STDERR) { untie(*STDERR); }"
" tie *STDOUT, 'EQEmuIO';"
" tie *STDERR, 'EQEmuIO';"
,FALSE);
"sub TIEHANDLE { my $me = bless {}, $_[0]; $me->PRINT('Creating '. $me); return($me); } "
"sub WRITE { } "
"sub PRINTF { my $me = shift; my $fmt = shift; $me->PRINT(sprintf($fmt, @_)); } "
"sub CLOSE { my $me = shift; $me->PRINT('Closing '.$me); } "
"sub DESTROY { my $me = shift; $me->PRINT('Destroying '.$me); } "
"package quest;"
" if(tied *STDOUT) { untie(*STDOUT); }"
" if(tied *STDERR) { untie(*STDERR); }"
" tie *STDOUT, 'EQEmuIO';"
" tie *STDERR, 'EQEmuIO';", FALSE);
#endif //EMBPERL_IO_CAPTURE
#ifdef EMBPERL_PLUGIN
eval_pv(
"package plugin; "
,FALSE
"package plugin; ", FALSE
);
LogQuests("Loading perlemb plugins");
try
{
try {
std::string perl_command;
perl_command = "main::eval_file('plugin', '" + Config->PluginPlFile + "');";
eval_pv(perl_command.c_str(), FALSE);
}
catch(std::string& e)
{
catch (std::string& e) {
LogQuests("Warning [{}]: [{}]", Config->PluginPlFile, e);
}
try
{
try {
//should probably read the directory in c, instead, so that
//I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins
std::string perl_command =
"if(opendir(D,'" + path.GetPluginsPath() +"')) { "
const std::string& perl_command = (
"if(opendir(D,'" +
path.GetPluginsPath() +
"')) { "
" my @d = readdir(D);"
" closedir(D);"
" foreach(@d){ "
" main::eval_file('plugin','" + path.GetPluginsPath() + "/'.$_)if/\\.pl$/;"
" main::eval_file('plugin','" +
path.GetPluginsPath() +
"/'.$_)if/\\.pl$/;"
" }"
"}";
eval_pv(perl_command.c_str(),FALSE);
"}");
eval_pv(perl_command.c_str(), FALSE);
}
catch(std::string& e)
{
catch (std::string& e) {
LogQuests("Warning [{}]", e);
}
#endif //EMBPERL_PLUGIN
in_use = false;
}
Embperl::~Embperl()
{
in_use = true;
#ifdef EMBPERL_IO_CAPTURE
eval_pv(
"package quest;"
" if(tied *STDOUT) { untie(*STDOUT); }"
" if(tied *STDERR) { untie(*STDERR); }"
,FALSE);
" if(tied *STDERR) { untie(*STDERR); }", FALSE);
#endif
PL_perl_destruct_level = 1;
perl_destruct(my_perl);
@@ -181,17 +175,15 @@ Embperl::~Embperl()
my_perl = NULL;
}
void Embperl::Reinit() {
in_use = true;
void Embperl::Reinit()
{
PERL_SET_CONTEXT(my_perl);
PERL_SET_INTERP(my_perl);
PL_perl_destruct_level = 1;
perl_destruct(my_perl);
perl_free(my_perl);
my_perl = NULL;
//Now reinit...
DoInit();
in_use = false;
}
void Embperl::init_eval_file(void)
@@ -201,38 +193,30 @@ void Embperl::init_eval_file(void)
"no warnings 'all';"
"use Symbol qw(delete_package);"
"sub eval_file {"
"my($package, $filename) = @_;"
"$filename=~s/\'//g;"
"if(! -r $filename) { print \"Unable to read perl file '$filename'\\n\"; return; }"
"my $mtime = -M $filename;"
"if(defined $Cache{$package}{mtime}&&$Cache{$package}{mtime} <= $mtime && !($package eq 'plugin')){"
" return;"
"} else {"
// we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require './$filename'; \");"
" print $@ if $@;"
/* "local *FH;open FH, $filename or die \"open '$filename' $!\";"
"local($/) = undef;my $sub = <FH>;close FH;"
"my $eval = qq{package $package; sub handler { $sub; }};"
"{ my($filename,$mtime,$package,$sub); eval $eval; }"
"die $@ if $@;"
"$Cache{$package}{mtime} = $mtime; ${$package.'::isloaded'} = 1;}"
*/
"}"
"my($package, $filename) = @_;"
"$filename=~s/\'//g;"
"if(! -r $filename) { print \"Unable to read perl file '$filename'\\n\"; return; }"
"my $mtime = -M $filename;"
"if(defined $Cache{$package}{mtime}&&$Cache{$package}{mtime} <= $mtime && !($package eq 'plugin')){"
" return;"
"} else {"
// we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require './$filename'; \");"
" print $@ if $@;"
"}"
,FALSE);
}
"}", FALSE);
}
int Embperl::eval_file(const char * packagename, const char * filename)
int Embperl::eval_file(const char* package_name, const char* filename)
{
std::vector<std::string> args;
args.push_back(packagename);
args.push_back(package_name);
args.push_back(filename);
return dosub("main::eval_file", &args);
}
int Embperl::dosub(const char * subname, const std::vector<std::string> * args, int mode)
int Embperl::dosub(const char* sub_name, const std::vector<std::string>* args, int mode)
{
dSP;
int ret_value = 0;
@@ -242,27 +226,29 @@ int Embperl::dosub(const char * subname, const std::vector<std::string> * args,
ENTER;
SAVETMPS;
PUSHMARK(SP);
if (args && !args->empty()) {
for (auto i = args->begin(); i != args->end(); ++i) {
XPUSHs(sv_2mortal(newSVpv(i->c_str(), i->length())));
}
}
PUTBACK;
count = call_pv(subname, mode);
count = call_pv(sub_name, mode);
SPAGAIN;
if (SvTRUE(ERRSV)) {
error = SvPV_nolen(ERRSV);
POPs;
}
else {
} else {
if (count == 1) {
SV *ret = POPs;
SV* ret = POPs;
if (SvTYPE(ret) == SVt_IV) {
IV v = SvIV(ret);
ret_value = v;
}
PUTBACK;
}
}
@@ -273,8 +259,8 @@ int Embperl::dosub(const char * subname, const std::vector<std::string> * args,
// not sure why we pass this as blind args, strange
// check for syntax errors
if (args && !args->empty()) {
const std::string &filename = args->back();
std::string sub = subname;
const std::string& filename = args->back();
std::string sub = sub_name;
if (sub == "main::eval_file" && !filename.empty() && File::Exists(filename)) {
BenchTimer benchmark;
@@ -286,8 +272,10 @@ int Embperl::dosub(const char * subname, const std::vector<std::string> * args,
std::string syntax_error = Process::execute(
fmt::format("{} -c {} 2>&1", perl, filename)
);
LogQuests("Perl eval [{}] took [{}]", filename, benchmark.elapsed());
syntax_error = Strings::Trim(syntax_error);
if (!Strings::Contains(syntax_error, "syntax OK")) {
syntax_error += SvPVX(ERRSV);
throw syntax_error;
@@ -305,19 +293,22 @@ int Embperl::dosub(const char * subname, const std::vector<std::string> * args,
}
//evaluate an expression. throw error on fail
int Embperl::eval(const char * code)
int Embperl::eval(const char* code)
{
std::vector<std::string> arg;
arg.push_back(code);
return dosub("main::my_eval", &arg, G_SCALAR|G_EVAL|G_KEEPERR);
return dosub("main::my_eval", &arg, G_SCALAR | G_EVAL | G_KEEPERR);
}
bool Embperl::SubExists(const char *package, const char *sub) {
HV *stash = gv_stashpv(package, false);
if(!stash)
return(false);
bool Embperl::SubExists(const char* package, const char* sub)
{
HV* stash = gv_stashpv(package, false);
if (!stash) {
return (false);
}
int len = strlen(sub);
return(hv_exists(stash, sub, len));
return (hv_exists(stash, sub, len));
}
#ifdef EMBPERL_IO_CAPTURE
@@ -331,8 +322,8 @@ XS(XS_EQEmuIO_PRINT)
}
for (int r = 1; r < items; r++) {
char *str = SvPV_nolen(ST(r));
char *cur = str;
char* str = SvPV_nolen(ST(r));
char* cur = str;
/* Strip newlines from log message 'str' */
*std::remove(str, str + strlen(str), '\n') = '\0';