2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2025-01-06 03:55:45 +03:00
metamod-r/metamod/src/mlist.cpp

984 lines
24 KiB
C++
Raw Normal View History

2016-07-26 03:22:47 +03:00
#include "precompiled.h"
2016-07-04 09:07:29 +03:00
// Constructor
2016-07-26 03:22:47 +03:00
MPluginList::MPluginList(const char *ifile)
2016-07-04 09:07:29 +03:00
: size(MAX_PLUGINS), endlist(0)
{
// store filename of ini file
2016-07-26 03:22:47 +03:00
Q_strncpy(inifile, ifile, sizeof(inifile) - 1);
inifile[sizeof(inifile) - 1] = '\0';
2016-07-04 09:07:29 +03:00
// initialize array
2016-07-26 03:22:47 +03:00
for (int i = 0; i < size; i++)
{
2016-07-04 09:07:29 +03:00
//reset to empty
2016-07-26 03:22:47 +03:00
plist[i].index = i + 1;
2016-07-04 09:07:29 +03:00
reset_plugin(&plist[i]);
}
2016-07-26 03:22:47 +03:00
endlist = 0;
2016-07-04 09:07:29 +03:00
}
// Resets plugin to empty
2016-07-26 03:22:47 +03:00
void MPluginList::reset_plugin(MPlugin *pl_find)
{
2016-07-04 09:07:29 +03:00
//calculate index
2016-07-26 03:22:47 +03:00
int i = pl_find - &plist[0];
2016-07-04 09:07:29 +03:00
//free any pointers first
pl_find->free_api_pointers();
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
//set zero
2016-07-04 10:11:20 +03:00
Q_memset(pl_find, 0, sizeof(*pl_find));
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
pl_find->index=i+1; // 1-based
}
// Find a plugin based on the plugin index #.
// meta_errno values:
// - ME_ARGUMENT invalid pindex
// - ME_NOTFOUND couldn't find a matching plugin
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find(int pindex)
{
if (pindex <= 0)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
MPlugin *pfound = &plist[pindex - 1];
if (pfound->status < PL_VALID)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
else
2016-07-26 03:22:47 +03:00
return pfound;
2016-07-04 09:07:29 +03:00
}
// Find a plugin based on the plugin handle.
// meta_errno values:
// - ME_ARGUMENT invalid pindex
// - ME_NOTFOUND couldn't find a matching plugin
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find(DLHANDLE handle)
{
if (!handle)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (plist[i].handle == handle)
return &plist[i];
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
// Clear source_plugin_index on all matching plugins
2016-07-26 03:22:47 +03:00
void MPluginList::clear_source_plugin_index(int source_index)
{
if (source_index <= 0)
2016-07-04 09:07:29 +03:00
return;
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (plist[i].source_plugin_index == source_index)
2016-07-04 09:07:29 +03:00
plist[i].source_plugin_index = -1;
}
}
// Find if any plugin has been loaded by plugin 'source_index'
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::found_child_plugins(int source_index)
{
if (source_index <= 0)
return mFALSE;
for (int i = 0; i < endlist; i++)
{
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (plist[i].source_plugin_index == source_index)
return mTRUE;
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
// Try make endlist lower (called after plugin unload)
2016-07-26 03:22:47 +03:00
void MPluginList::trim_list()
{
if (endlist <= 0)
2016-07-04 09:07:29 +03:00
return;
2016-07-26 03:22:47 +03:00
int n = 0;
for (int i = 0; i < endlist; i++)
{
if (plist[i].status == PL_EMPTY)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
n = i + 1;
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
if (n < endlist)
endlist = n;
2016-07-04 09:07:29 +03:00
}
// Find a plugin with the given plid.
// meta_errno values:
// - ME_ARGUMENT null plid_t
// - ME_NOTFOUND couldn't find a matching plugin
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find(plid_t id)
{
if (!id)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (plist[i].info == id)
return &plist[i];
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
// Find a plugin with the given pathname.
// meta_errno values:
// - ME_ARGUMENT null path
// - ME_NOTFOUND couldn't find a matching plugin
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find(const char *findpath)
{
if (!findpath)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_DEBUG(8, ("Looking for loaded plugin with dlfnamepath: %s", findpath));
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
2016-07-04 09:07:29 +03:00
META_DEBUG(9, ("Looking at: plugin %s loadedpath: %s", plist[i].file, plist[i].pathname));
2016-07-26 03:22:47 +03:00
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (!Q_strcmp(plist[i].pathname, findpath))
{
2016-07-04 09:07:29 +03:00
META_DEBUG(8, ("Found loaded plugin %s", plist[i].file));
2016-07-26 03:22:47 +03:00
return &plist[i];
2016-07-04 09:07:29 +03:00
}
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_DEBUG(8, ("No loaded plugin found with path: %s", findpath));
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
// Find a plugin that uses the given memory location.
// meta_errno values:
// - ME_ARGUMENT null memptr
// - ME_NOTFOUND couldn't find a matching plugin
// - errno's from DLFNAME()
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find_memloc(void *memptr)
{
#ifdef _WIN32
DLHANDLE dlhandle;
2016-07-04 09:07:29 +03:00
2016-07-26 03:22:47 +03:00
if (!memptr)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
if (!(dlhandle = get_module_handle_of_memptr(memptr)))
{
2016-07-04 09:07:29 +03:00
META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr));
2016-07-26 03:22:47 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
return find(dlhandle);
2016-07-04 09:07:29 +03:00
#else
2016-07-26 03:22:47 +03:00
const char *dlfile;
if (!memptr)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
if (!(dlfile = DLFNAME(memptr)))
{
2016-07-04 09:07:29 +03:00
META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr));
2016-07-26 03:22:47 +03:00
// meta_errno should be already set in DLFNAME
return NULL;
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
return find(dlfile);
2016-07-04 09:07:29 +03:00
#endif
}
2016-07-26 03:22:47 +03:00
// Find a plugin with non-ambiguous prefix string matching desc, file,
2016-07-04 09:07:29 +03:00
// name, or logtag.
// meta_errno values:
// - ME_ARGUMENT null prefix
// - ME_NOTFOUND couldn't find a matching plugin
// - ME_NOTUNIQ found multiple matches; no unique match
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find_match(const char *prefix)
{
int len;
2016-07-04 09:07:29 +03:00
MPlugin *iplug, *pfound;
char buf[NAME_MAX];
2016-07-26 03:22:47 +03:00
if (!prefix)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
pfound = nullptr;
len = Q_strlen(prefix);
2016-07-04 09:07:29 +03:00
safevoid_snprintf(buf, sizeof(buf), "mm_%s", prefix);
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
iplug = &plist[i];
if (iplug->status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (iplug->info && Q_strnicmp(iplug->info->name, prefix, len) == 0)
{
if (pfound)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTUNIQ);
2016-07-26 03:22:47 +03:00
pfound = iplug;
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
else if (Q_strnicmp(iplug->desc, prefix, len) == 0)
{
if (pfound)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTUNIQ);
2016-07-26 03:22:47 +03:00
pfound = iplug;
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
else if (Q_strnicmp(iplug->file, prefix, len) == 0)
{
if (pfound)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTUNIQ);
2016-07-26 03:22:47 +03:00
pfound = iplug;
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
else if (Q_strnicmp(iplug->file, buf, Q_strlen(buf)) == 0)
{
if (pfound)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTUNIQ);
2016-07-26 03:22:47 +03:00
pfound = iplug;
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
else if (iplug->info && Q_strnicmp(iplug->info->logtag, prefix, len) == 0)
2016-07-04 09:07:29 +03:00
{
2016-07-26 03:22:47 +03:00
if (pfound)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTUNIQ);
2016-07-26 03:22:47 +03:00
pfound = iplug;
2016-07-04 09:07:29 +03:00
continue;
}
}
2016-07-26 03:22:47 +03:00
if (pfound)
return pfound;
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
2016-07-26 03:22:47 +03:00
// Find a plugin with same file, logtag, desc or significant
2016-07-04 09:07:29 +03:00
// prefix of file. Uses the platform_match() method of MPlugin.
// meta_errno values:
// - ME_ARGUMENT null prefix
// - ME_NOTFOUND couldn't find a matching plugin
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::find_match(MPlugin *pmatch)
{
2016-07-04 09:07:29 +03:00
MPlugin *iplug, *pfound;
2016-07-26 03:22:47 +03:00
if (!pmatch)
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_ARGUMENT);
2016-07-26 03:22:47 +03:00
pfound = nullptr;
for (int i = 0; i < endlist; i++)
{
iplug = &plist[i];
if (pmatch->platform_match(iplug))
{
2016-07-04 09:07:29 +03:00
pfound=iplug;
break;
}
}
2016-07-26 03:22:47 +03:00
if (pfound)
return pfound;
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
// Add a plugin to the list.
// meta_errno values:
// - ME_MAXREACHED reached max plugins
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::add(MPlugin *padd)
{
2016-07-04 09:07:29 +03:00
int i;
MPlugin *iplug;
// Find either:
// - a slot in the list that's not being used
// - the end of the list
2016-07-26 03:22:47 +03:00
for (i = 0; i < endlist && plist[i].status != PL_EMPTY; i++) {}
2016-07-04 09:07:29 +03:00
// couldn't find a slot to use
2016-07-26 03:22:47 +03:00
if (i == size)
{
META_WARNING("Couldn't add plugin '%s' to list; reached max plugins (%d)", padd->file, i);
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(NULL, ME_MAXREACHED);
}
// if we found the end of the list, advance end marker
2016-07-26 03:22:47 +03:00
if (i == endlist)
2016-07-04 09:07:29 +03:00
endlist++;
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
iplug = &plist[i];
// copy filename into this free slot
2016-07-26 03:22:47 +03:00
Q_strncpy(iplug->filename, padd->filename, sizeof(iplug->filename) - 1);
iplug->filename[sizeof(iplug->filename) - 1] = '\0';
2016-07-04 09:07:29 +03:00
// Copy file offset ptr.
// Can't just copy ptr, as it points to offset in padd, which will go
// away; need to point to corresponding offset in iplug.
iplug->file = iplug->filename + (padd->file - padd->filename);
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// copy description
2016-07-26 03:22:47 +03:00
Q_strncpy(iplug->desc, padd->desc, sizeof(iplug->desc) - 1);
iplug->desc[sizeof(iplug->desc) - 1] = '\0';
2016-07-04 09:07:29 +03:00
// copy pathname
2016-07-26 03:22:47 +03:00
Q_strncpy(iplug->pathname, padd->pathname, sizeof(iplug->pathname) - 1);
iplug->pathname[sizeof(iplug->pathname) - 1] = '\0';
2016-07-04 09:07:29 +03:00
// copy source
2016-07-26 03:22:47 +03:00
iplug->source = padd->source;
2016-07-04 09:07:29 +03:00
// copy loader-plugin
2016-07-26 03:22:47 +03:00
iplug->source_plugin_index = padd->source_plugin_index;
2016-07-04 09:07:29 +03:00
// copy status
2016-07-26 03:22:47 +03:00
iplug->status = padd->status;
2016-07-04 09:07:29 +03:00
2016-07-26 03:22:47 +03:00
return iplug;
}
2016-07-04 09:07:29 +03:00
// Read plugins.ini at server startup.
// meta_errno values:
// - ME_NOFILE ini file missing or empty
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::ini_startup()
{
2016-07-04 09:07:29 +03:00
FILE *fp;
char line[MAX_STRBUF_LEN];
int n, ln;
MPlugin *pmatch;
2016-07-26 03:22:47 +03:00
if (!valid_gamedir_file(inifile))
{
2016-07-04 09:07:29 +03:00
META_WARNING("ini: Metamod plugins file empty or missing: %s", inifile);
RETURN_ERRNO(mFALSE, ME_NOFILE);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
full_gamedir_path(inifile, inifile);
2016-07-26 03:22:47 +03:00
fp = fopen(inifile, "r");
if (!fp)
{
META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, strerror(errno));
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(mFALSE, ME_NOFILE);
}
META_LOG("ini: Begin reading plugins list: %s", inifile);
2016-07-26 03:22:47 +03:00
for (n = 0, ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++)
{
2016-07-04 09:07:29 +03:00
// Remove line terminations.
char *cp;
2016-07-26 03:22:47 +03:00
if ((cp = Q_strrchr(line, '\r')))
*cp = '\0';
if ((cp = Q_strrchr(line, '\n')))
*cp = '\0';
2016-07-04 09:07:29 +03:00
// Parse directly into next entry in array
2016-07-26 03:22:47 +03:00
if (!plist[n].ini_parseline(line))
{
if (meta_errno == ME_FORMAT)
META_WARNING("ini: Skipping malformed line %d of %s", ln, inifile);
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// Check for a duplicate - an existing entry with this pathname.
2016-07-26 03:22:47 +03:00
if (find(plist[n].pathname))
{
2016-07-04 09:07:29 +03:00
// Should we check platform specific level here?
2016-07-26 03:22:47 +03:00
META_INFO("ini: Skipping duplicate plugin, line %d of %s: %s", ln, inifile, plist[n].pathname);
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// Check for a matching platform with different platform specifics
// level.
2016-07-26 03:22:47 +03:00
if ((pmatch = find_match(&plist[n])))
{
if (pmatch->pfspecific >= plist[n].pfspecific)
{
META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pmatch->pfspecific, plist[n].pfspecific));
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
META_DEBUG(1, ("ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->pfspecific, plist[n].pfspecific));
2016-07-04 09:07:29 +03:00
//reset to empty
reset_plugin(pmatch);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
plist[n].action=PA_LOAD;
META_LOG("ini: Read plugin config for: %s", plist[n].desc);
n++;
2016-07-26 03:22:47 +03:00
endlist = n; // mark end of list
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", inifile, n);
2016-07-04 09:07:29 +03:00
fclose(fp);
2016-07-26 03:22:47 +03:00
if (!n)
{
2016-07-04 09:07:29 +03:00
META_WARNING("ini: Warning; no plugins found to load?");
}
2016-07-26 03:22:47 +03:00
return mTRUE;
2016-07-04 09:07:29 +03:00
}
// Re-read plugins.ini looking for added/deleted/changed plugins.
// meta_errno values:
// - ME_NOFILE ini file missing or empty
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::ini_refresh()
{
2016-07-04 09:07:29 +03:00
FILE *fp;
char line[MAX_STRBUF_LEN];
int n, ln;
MPlugin pl_temp;
MPlugin *pl_found, *pl_added;
2016-07-26 03:22:47 +03:00
fp = fopen(inifile, "r");
if (!fp)
{
META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, strerror(errno));
2016-07-04 09:07:29 +03:00
RETURN_ERRNO(mFALSE, ME_NOFILE);
}
META_LOG("ini: Begin re-reading plugins list: %s", inifile);
2016-07-26 03:22:47 +03:00
for (n = 0, ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++)
2016-07-04 09:07:29 +03:00
{
// Remove line terminations.
char *cp;
2016-07-26 03:22:47 +03:00
if ((cp = Q_strrchr(line, '\r')))
*cp = '\0';
if ((cp = Q_strrchr(line, '\n')))
*cp = '\0';
2016-07-04 09:07:29 +03:00
// Parse into a temp plugin
2016-07-04 10:11:20 +03:00
Q_memset(&pl_temp, 0, sizeof(pl_temp));
2016-07-26 03:22:47 +03:00
if (!pl_temp.ini_parseline(line))
{
if (meta_errno == ME_FORMAT)
{
META_WARNING("ini: Skipping malformed line %d of %s", ln, inifile);
}
2016-07-04 09:07:29 +03:00
continue;
}
// Try to find plugin with this pathname in the current list of
// plugins.
2016-07-26 03:22:47 +03:00
if (!(pl_found = find(pl_temp.pathname)))
{
2016-07-04 09:07:29 +03:00
// Check for a matching platform with higher platform specifics
// level.
2016-07-26 03:22:47 +03:00
if ((pl_found = find_match(&pl_temp)))
{
if (pl_found->pfspecific >= pl_temp.pfspecific)
{
META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pl_found->pfspecific, pl_temp.pfspecific));
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
if (PA_LOAD == pl_found->action)
{
META_DEBUG(1, ("ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->pfspecific, pl_temp.pfspecific));
2016-07-04 09:07:29 +03:00
//reset to empty
reset_plugin(pl_found);
}
2016-07-26 03:22:47 +03:00
else
{
META_DEBUG(1, ("ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->pfspecific, pl_temp.pfspecific));
2016-07-04 09:07:29 +03:00
continue;
}
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// new plugin; add to list
2016-07-26 03:22:47 +03:00
if ((pl_added = add(&pl_temp)))
{
2016-07-04 09:07:29 +03:00
// try to load this plugin at the next opportunity
2016-07-26 03:22:47 +03:00
pl_added->action = PA_LOAD;
2016-07-04 09:07:29 +03:00
}
else
// error details logged in add()
continue;
}
2016-07-26 03:22:47 +03:00
else
{
2016-07-04 09:07:29 +03:00
// This plugin is already in the current list of plugins.
// Pathname already matches. Recopy desc, if specified in
// plugins.ini.
2016-07-26 03:22:47 +03:00
if (pl_temp.desc[0] != '<')
{
Q_strncpy(pl_found->desc, pl_temp.desc, sizeof(pl_found->desc) - 1);
pl_found->desc[sizeof(pl_found->desc) - 1] = '\0';
}
2016-07-04 09:07:29 +03:00
// Check the file to see if it looks like it's been modified
// since we last loaded it.
2016-07-26 03:22:47 +03:00
if (!pl_found->newer_file())
{
if (meta_errno == ME_NOFILE)
{
META_WARNING("ini: Skipping plugin, couldn't stat file '%s': %s", pl_found->pathname, strerror(errno));
2016-07-04 09:07:29 +03:00
continue;
}
2016-07-26 03:22:47 +03:00
else
{
2016-07-04 09:07:29 +03:00
// File hasn't been updated.
// Keep plugin (don't let refresh() unload it).
2016-07-26 03:22:47 +03:00
pl_found->action = PA_KEEP;
2016-07-04 09:07:29 +03:00
}
}
// Newer file on disk.
2016-07-26 03:22:47 +03:00
else if (pl_found->status >= PL_OPENED)
{
2016-07-04 09:07:29 +03:00
META_DEBUG(2, ("ini: Plugin '%s' has newer file on disk", pl_found->desc));
2016-07-26 03:22:47 +03:00
pl_found->action = PA_RELOAD;
2016-07-04 09:07:29 +03:00
}
else
2016-07-26 03:22:47 +03:00
META_WARNING("ini: Plugin '%s' has newer file, but unexpected status (%s)", pl_found->desc, pl_found->str_status());
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
if (pl_found)
{
2016-07-04 09:07:29 +03:00
META_LOG("ini: Read plugin config for: %s", pl_found->desc);
}
2016-07-26 03:22:47 +03:00
else
{
2016-07-04 09:07:29 +03:00
META_LOG("ini: Read plugin config for: %s", pl_temp.desc);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
n++;
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", inifile, n);
fclose(fp);
2016-07-26 03:22:47 +03:00
if (!n)
{
2016-07-04 09:07:29 +03:00
META_WARNING("ini: Warning; no plugins found to load?");
}
2016-07-26 03:22:47 +03:00
return mTRUE;
2016-07-04 09:07:29 +03:00
}
// Load a plugin from plugin request.
// meta_errno values:
// - errno's from resolve()
// - ME_ALREADY this plugin already loaded
// - errno's from add()
// - errno's from load()
2016-07-26 03:22:47 +03:00
MPlugin *MPluginList::plugin_addload(plid_t plid, const char *fname, PLUG_LOADTIME now)
{
2016-07-04 09:07:29 +03:00
MPlugin pl_temp;
MPlugin *pl_found, *pl_added, *pl_loader;
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// Find loader plugin
2016-07-26 03:22:47 +03:00
if (!(pl_loader = find(plid)))
{
2016-07-04 09:07:29 +03:00
// Couldn't find a matching file on disk
META_DEBUG(1, ("Couldn't find plugin that gave this loading request!"));
// meta_errno should be already set in resolve()
RETURN_ERRNO(NULL, ME_BADREQ);
}
2016-07-26 03:22:47 +03:00
2016-07-04 10:11:20 +03:00
Q_memset(&pl_temp, 0, sizeof(pl_temp));
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// copy filename
2016-07-26 03:22:47 +03:00
if (!pl_temp.plugin_parseline(fname, pl_loader->index))
{
2016-07-04 09:07:29 +03:00
// parse_plugin_load doesn't return mFALSE.
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// resolve given path into a file; accepts various "shortcut"
// pathnames.
2016-07-26 03:22:47 +03:00
if (pl_temp.resolve() != mTRUE)
{
2016-07-04 09:07:29 +03:00
// Couldn't find a matching file on disk
META_DEBUG(1, ("Couldn't resolve given path into a file: %s", pl_temp.file));
// meta_errno should be already set in resolve()
RETURN_ERRNO(NULL, ME_NOTFOUND);
}
// Try to find plugin with this pathname in the current list of
// plugins.
2016-07-26 03:22:47 +03:00
if ((pl_found = find(pl_temp.pathname)))
{
2016-07-04 09:07:29 +03:00
// Already in list
2016-07-26 03:22:47 +03:00
META_DEBUG(1, ("Plugin '%s' already in current list; file=%s desc='%s'",
2016-07-04 09:07:29 +03:00
pl_temp.file, pl_found->file, pl_found->desc));
RETURN_ERRNO(NULL, ME_ALREADY);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// new plugin; add to list
2016-07-26 03:22:47 +03:00
if (!(pl_added = add(&pl_temp)))
{
2016-07-04 09:07:29 +03:00
META_DEBUG(1, ("Couldn't add plugin '%s' to list; see log", pl_temp.desc));
// meta_errno should be already set in add()
2016-07-26 03:22:47 +03:00
return NULL;
2016-07-04 09:07:29 +03:00
}
// try to load new plugin (setting 'must load now')
2016-07-26 03:22:47 +03:00
pl_added->action = PA_LOAD;
if (!pl_added->load(now))
{
2016-07-04 09:07:29 +03:00
// load failed
2016-07-26 03:22:47 +03:00
if (meta_errno == ME_NOTALLOWED || meta_errno == ME_DELAYED)
{
META_DEBUG(1, ("Plugin '%s' couldn't attach; only allowed %s",
2016-07-04 09:07:29 +03:00
pl_added->desc, pl_added->str_loadable(SL_ALLOWED)));
pl_added->clear();
}
2016-07-26 03:22:47 +03:00
else if (pl_added->status == PL_OPENED)
2016-07-04 09:07:29 +03:00
META_DEBUG(1, ("Opened plugin '%s', but failed to attach; see log", pl_added->desc));
else
META_DEBUG(1, ("Couldn't load plugin '%s'; see log", pl_added->desc));
// meta_errno should be already set in load()
2016-07-26 03:22:47 +03:00
return NULL;
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_DEBUG(1, ("Loaded plugin '%s' successfully", pl_added->desc));
meta_errno = ME_NOERROR;
2016-07-26 03:22:47 +03:00
return pl_added;
2016-07-04 09:07:29 +03:00
}
// Load a plugin from a console command.
// meta_errno values:
// - errno's from cmd_parseline()
// - errno's from resolve()
// - ME_ALREADY this plugin already loaded
// - errno's from add()
// - errno's from load()
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::cmd_addload(const char *args)
{
2016-07-04 09:07:29 +03:00
MPlugin pl_temp;
MPlugin *pl_found, *pl_added;
2016-07-26 03:22:47 +03:00
2016-07-04 10:11:20 +03:00
Q_memset(&pl_temp, 0, sizeof(pl_temp));
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
// XXX move back to comands_meta ?
// parse into a temp plugin
2016-07-26 03:22:47 +03:00
if (pl_temp.cmd_parseline(args) != mTRUE)
{
2016-07-04 09:07:29 +03:00
META_CONS("Couldn't parse 'meta load' arguments: %s", args);
// meta_errno should be already set in cmd_parseline()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
// resolve given path into a file; accepts various "shortcut"
// pathnames.
2016-07-26 03:22:47 +03:00
if (pl_temp.resolve() != mTRUE)
{
2016-07-04 09:07:29 +03:00
// Couldn't find a matching file on disk
2016-07-26 03:22:47 +03:00
META_CONS("Couldn't resolve given path into a file: %s",
2016-07-04 09:07:29 +03:00
pl_temp.file);
// meta_errno should be already set in resolve()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
// Try to find plugin with this pathname in the current list of
// plugins.
2016-07-26 03:22:47 +03:00
if ((pl_found=find(pl_temp.pathname)))
{
2016-07-04 09:07:29 +03:00
// Already in list
2016-07-26 03:22:47 +03:00
META_CONS("Plugin '%s' already in current list; file=%s desc='%s'",
2016-07-04 09:07:29 +03:00
pl_temp.file, pl_found->file, pl_found->desc);
RETURN_ERRNO(mFALSE, ME_ALREADY);
}
// new plugin; add to list
2016-07-26 03:22:47 +03:00
if (!(pl_added=add(&pl_temp)))
{
2016-07-04 09:07:29 +03:00
META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.desc);
// meta_errno should be already set in add()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
// try to load new plugin
pl_added->action=PA_LOAD;
2016-07-26 03:22:47 +03:00
if (!pl_added->load(PT_ANYTIME))
{
2016-07-04 09:07:29 +03:00
// load failed
2016-07-26 03:22:47 +03:00
if (meta_errno==ME_DELAYED)
META_CONS("Loaded plugin '%s', but will wait to become active, %s", pl_added->desc, pl_added->str_loadable(SL_ALLOWED));
else if (meta_errno==ME_NOTALLOWED)
{
META_CONS("Plugin '%s' couldn't attach; only allowed %s", pl_added->desc, pl_added->str_loadable(SL_ALLOWED));
2016-07-04 09:07:29 +03:00
pl_added->clear();
}
2016-07-26 03:22:47 +03:00
else if (pl_added->status == PL_OPENED)
2016-07-04 09:07:29 +03:00
META_CONS("Opened plugin '%s', but failed to attach; see log", pl_added->desc);
else
META_CONS("Couldn't load plugin '%s'; see log", pl_added->desc);
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
show();
// meta_errno should be already set in load()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_CONS("Loaded plugin '%s' successfully", pl_added->desc);
show();
2016-07-26 03:22:47 +03:00
return mTRUE;
2016-07-04 09:07:29 +03:00
}
// Load plugins at startup.
// meta_errno values:
// - errno's from ini_startup()
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::load()
{
if (!ini_startup())
{
2016-07-04 09:07:29 +03:00
META_WARNING("Problem loading plugins.ini: %s", inifile);
// meta_errno should be already set in ini_startup()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
META_LOG("dll: Loading plugins...");
2016-07-26 03:22:47 +03:00
int n = 0;
for (int i = 0; i < endlist; i++)
{
if (plist[i].status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (plist[i].load(PT_STARTUP) == mTRUE)
2016-07-04 09:07:29 +03:00
n++;
else
// all plugins should be loadable at startup...
META_WARNING("dll: Failed to load plugin '%s'", plist[i].file);
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_LOG("dll: Finished loading %d plugins", n);
2016-07-26 03:22:47 +03:00
return mTRUE;
2016-07-04 09:07:29 +03:00
}
// Update list of loaded plugins from ini file, and load any new/changed plugins.
// meta_errno values:
// - errno's from ini_refresh()
2016-07-26 03:22:47 +03:00
mBOOL MPluginList::refresh(PLUG_LOADTIME now)
{
int i, ndone = 0, nkept = 0, nloaded = 0, nunloaded = 0, nreloaded = 0, ndelayed = 0;
2016-07-04 09:07:29 +03:00
MPlugin *iplug;
2016-07-26 03:22:47 +03:00
if (!ini_refresh())
{
2016-07-04 09:07:29 +03:00
META_WARNING("dll: Problem reloading plugins.ini: %s", inifile);
// meta_errno should be already set in ini_refresh()
2016-07-26 03:22:47 +03:00
return mFALSE;
2016-07-04 09:07:29 +03:00
}
META_LOG("dll: Updating plugins...");
2016-07-26 03:22:47 +03:00
for (i = 0; i < endlist; i++)
{
iplug = &plist[i];
if (iplug->status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
switch (iplug->action)
{
case PA_KEEP:
META_DEBUG(1, ("Keeping plugin '%s'", iplug->desc));
iplug->action = PA_NONE;
nkept++;
break;
case PA_LOAD:
META_DEBUG(1, ("Loading plugin '%s'", iplug->desc));
if (iplug->load(now))
nloaded++;
else if (meta_errno == ME_DELAYED)
ndelayed++;
break;
case PA_RELOAD:
META_DEBUG(1, ("Reloading plugin '%s'", iplug->desc));
if (iplug->reload(now, PNL_FILE_NEWER))
nreloaded++;
else if (meta_errno == ME_DELAYED)
ndelayed++;
break;
case PA_NONE:
// If previously loaded from ini, but apparently removed from new ini.
if (iplug->source == PS_INI && iplug->status >= PL_RUNNING)
{
META_DEBUG(1, ("Unloading plugin '%s'", iplug->desc));
iplug->action = PA_UNLOAD;
if (iplug->unload(now, PNL_INI_DELETED, PNL_INI_DELETED))
2016-07-04 09:07:29 +03:00
nunloaded++;
2016-07-26 03:22:47 +03:00
else if (meta_errno == ME_DELAYED)
2016-07-04 09:07:29 +03:00
ndelayed++;
2016-07-26 03:22:47 +03:00
}
break;
case PA_ATTACH:
// Previously requested attach, but was delayed?
META_DEBUG(1, ("Retrying attach plugin '%s'", iplug->desc));
if (iplug->retry(now, PNL_DELAYED))
nloaded++;
else if (meta_errno == ME_DELAYED)
ndelayed++;
break;
case PA_UNLOAD:
// Previously requested unload, but was delayed?
META_DEBUG(1, ("Retrying unload plugin '%s'", iplug->desc));
if (iplug->retry(now, PNL_DELAYED))
nunloaded++;
else if (meta_errno == ME_DELAYED)
ndelayed++;
break;
case PA_NULL:
META_WARNING("dll: Unexpected action for plugin '%s': '%s'", iplug->desc, iplug->str_action());
break;
default:
META_WARNING("dll: Unrecognized action for plugin '%s': '%s'", iplug->desc, iplug->str_action());
break;
2016-07-04 09:07:29 +03:00
}
ndone++;
}
2016-07-26 03:22:47 +03:00
META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed);
return mTRUE;
2016-07-04 09:07:29 +03:00
}
// Re-enable any plugins currently paused.
// meta_errno values:
// - none
2016-07-26 03:22:47 +03:00
void MPluginList::unpause_all()
{
2016-07-04 09:07:29 +03:00
MPlugin *iplug;
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
iplug = &plist[i];
if (iplug->status == PL_PAUSED)
2016-07-04 09:07:29 +03:00
iplug->unpause();
}
}
// Retry any pending actions on plugins, for instance load/unload delayed
// until changelevel.
// meta_errno values:
// - none
2016-07-26 03:22:47 +03:00
void MPluginList::retry_all(PLUG_LOADTIME now)
{
2016-07-04 09:07:29 +03:00
MPlugin *iplug;
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
iplug = &plist[i];
if (iplug->action != PA_NONE)
2016-07-04 09:07:29 +03:00
iplug->retry(now, PNL_DELAYED);
}
}
// List plugins and information about them in a formatted table.
// meta_errno values:
// - none
2016-07-26 03:22:47 +03:00
void MPluginList::show(int source_index)
{
int n = 0, r = 0;
2016-07-04 09:07:29 +03:00
MPlugin *pl;
2016-07-26 03:22:47 +03:00
char desc[15 + 1], file[16 + 1], vers[7 + 1]; // plus 1 for term null
if (source_index <= 0)
2016-07-04 09:07:29 +03:00
META_CONS("Currently loaded plugins:");
else
META_CONS("Child plugins:");
2016-07-26 03:22:47 +03:00
META_CONS(" %*s %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, "", sizeof(desc) - 1, "description", "stat", "pend",
sizeof(file) - 1, "file", sizeof(vers) - 1, "ers", 2 + WIDTH_MAX_PLUGINS, "src", "load ", "unlod");
for (int i = 0; i < endlist; i++)
{
pl = &plist[i];
if (pl->status < PL_VALID)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
if (source_index > 0 && pl->source_plugin_index != source_index)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
Q_strncpy(desc, pl->desc, sizeof(desc) - 1);
desc[sizeof(desc) - 1] = '\0';
Q_strncpy(file, pl->file, sizeof(file) - 1);
file[sizeof(file) - 1] = '\0';
if (pl->info && pl->info->version)
{
Q_strncpy(vers, pl->info->version, sizeof(vers) - 1);
vers[sizeof(vers) - 1] = '\0';
}
else
{
Q_strncpy(vers, " -", sizeof(vers) - 1);
vers[sizeof(vers) - 1] = '\0';
}
META_CONS(" [%*d] %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, pl->index,
sizeof(desc) - 1, desc, pl->str_status(ST_SHOW), pl->str_action(SA_SHOW), sizeof(file) - 1, file, sizeof(vers) - 1, vers,
2 + WIDTH_MAX_PLUGINS, pl->str_source(SO_SHOW), pl->str_loadable(SL_SHOW), pl->str_unloadable(SL_SHOW));
if (pl->status == PL_RUNNING)
2016-07-04 09:07:29 +03:00
r++;
n++;
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_CONS("%d plugins, %d running", n, r);
}
// List plugins and information to Player/client entity. Differs from the
// "meta list" console command in that:
// - Shows only "running" plugins, skipping any failed or paused plugins.
2016-07-26 03:22:47 +03:00
// - Limited info about each plugin, mostly the "public" info (name, author,
2016-07-04 09:07:29 +03:00
// etc).
// meta_errno values:
// - none
2016-07-26 03:22:47 +03:00
void MPluginList::show_client(edict_t *pEntity)
{
int n = 0;
2016-07-04 09:07:29 +03:00
MPlugin *pl;
META_CLIENT(pEntity, "Currently running plugins:");
2016-07-26 03:22:47 +03:00
for (int i = 0; i < endlist; i++)
{
pl = &plist[i];
if (pl->status != PL_RUNNING || !pl->info)
2016-07-04 09:07:29 +03:00
continue;
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
n++;
2016-07-26 03:22:47 +03:00
META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n,
pl->info->name ? pl->info->name : "<unknown>",
pl->info->version ? pl->info->version : "<?>",
pl->info->date ? pl->info->date : "<../../..>",
pl->info->author ? pl->info->author : "<unknown>",
pl->info->url ? pl->info->url : "<unknown>");
2016-07-04 09:07:29 +03:00
}
2016-07-26 03:22:47 +03:00
2016-07-04 09:07:29 +03:00
META_CLIENT(pEntity, "%d plugins", n);
}