Added search_getpackagename builtin to query which package a file is inside (flags&2 to get the gamedir of the package/gamedir too), also let the 'cvar' pseudo-cvar be queried via cvar_string.

This commit is contained in:
Shpoike 2020-07-19 01:36:32 +01:00
parent bdfdface5b
commit 5842eb70e8
3 changed files with 163 additions and 52 deletions

View file

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h" #include "quakedef.h"
#include "q_ctype.h" #include "q_ctype.h"
#include <errno.h> #include <errno.h>
#include <sys/stat.h>
#ifndef _WIN32 #ifndef _WIN32
#include <dirent.h> #include <dirent.h>
@ -559,11 +560,14 @@ float Q_atof (const char *str)
// Q_ftoa: convert IEEE 754 float to a base-10 string with "infinite" decimal places // Q_ftoa: convert IEEE 754 float to a base-10 string with "infinite" decimal places
void Q_ftoa(char *str, float in) void Q_ftoa(char *str, float in)
{ {
unsigned int i = *((int *)&in); struct {
float f;
unsigned int i;
} u = {in};
int signbit = (i & 0x80000000) >> 31; int signbit = (u.i & 0x80000000) >> 31;
int exp = (signed int)((i & 0x7F800000) >> 23) - 127; int exp = (signed int)((u.i & 0x7F800000) >> 23) - 127;
int mantissa = (i & 0x007FFFFF); int mantissa = (u.i & 0x007FFFFF);
if (exp == 128) // 255(NaN/Infinity bits) - 127(bias) if (exp == 128) // 255(NaN/Infinity bits) - 127(bias)
{ {
@ -604,6 +608,42 @@ void Q_ftoa(char *str, float in)
} }
} }
int wildcmp(const char *wild, const char *string)
{ //case-insensitive string compare with wildcards. returns true for a match.
while (*string)
{
if (*wild == '*')
{
if (*string == '/' || *string == '\\')
{
//* terminates if we get a match on the char following it, or if its a \ or / char
wild++;
continue;
}
if (wildcmp(wild+1, string))
return true;
string++;
}
else if ((q_tolower(*wild) == q_tolower(*string)) || (*wild == '?'))
{
//this char matches
wild++;
string++;
}
else
{
//failure
return false;
}
}
while (*wild == '*')
{
wild++;
}
return !*wild;
}
/* /*
============================================================================ ============================================================================
@ -2263,7 +2303,7 @@ void COM_ListSystemFiles(void *ctx, const char *gamedir, const char *ext, qboole
#endif #endif
} }
void COM_ListFiles(void *ctx, const char *gamedir, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize)) static void COM_ListFiles(void *ctx, searchpath_t *spath, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize, searchpath_t *spath))
{ {
char prefixdir[MAX_OSPATH]; char prefixdir[MAX_OSPATH];
char *sl; char *sl;
@ -2285,14 +2325,14 @@ void COM_ListFiles(void *ctx, const char *gamedir, const char *pattern, qboolean
char filestring[MAX_OSPATH]; char filestring[MAX_OSPATH];
WIN32_FIND_DATA fdat; WIN32_FIND_DATA fdat;
HANDLE fhnd; HANDLE fhnd;
q_snprintf (filestring, sizeof(filestring), "%s/%s%s", gamedir, prefixdir, pattern); q_snprintf (filestring, sizeof(filestring), "%s/%s%s", spath->filename, prefixdir, pattern);
fhnd = FindFirstFile(filestring, &fdat); fhnd = FindFirstFile(filestring, &fdat);
if (fhnd == INVALID_HANDLE_VALUE) if (fhnd == INVALID_HANDLE_VALUE)
return; return;
do do
{ {
q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, fdat.cFileName); q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, fdat.cFileName);
cb (ctx, filestring, Sys_FileTimeToTime(fdat.ftLastWriteTime), fdat.nFileSizeLow); cb (ctx, filestring, Sys_FileTimeToTime(fdat.ftLastWriteTime), fdat.nFileSizeLow, spath);
} while (FindNextFile(fhnd, &fdat)); } while (FindNextFile(fhnd, &fdat));
FindClose(fhnd); FindClose(fhnd);
} }
@ -2302,22 +2342,60 @@ void COM_ListFiles(void *ctx, const char *gamedir, const char *pattern, qboolean
DIR *dir_p; DIR *dir_p;
struct dirent *dir_t; struct dirent *dir_t;
q_snprintf (filestring, sizeof(filestring), "%s/%s", gamedir, prefixdir); q_snprintf (filestring, sizeof(filestring), "%s/%s", spath->filename, prefixdir);
dir_p = opendir(filestring); dir_p = opendir(filestring);
if (dir_p == NULL) if (dir_p == NULL)
return; return;
while ((dir_t = readdir(dir_p)) != NULL) while ((dir_t = readdir(dir_p)) != NULL)
{ {
if (*dir_t->d_name == '.') //ignore hidden paths... and parent etc weirdness.
continue;
if (!fnmatch(pattern, dir_t->d_name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD)) if (!fnmatch(pattern, dir_t->d_name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD))
{ {
struct stat s;
q_snprintf (filestring, sizeof(filestring), "%s/%s%s", spath->filename, prefixdir, dir_t->d_name);
if (stat(filestring, &s) < 0)
memset(&s, 0, sizeof(s));
q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, dir_t->d_name); q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, dir_t->d_name);
cb (ctx, filestring, 0, 0); cb (ctx, filestring, s.st_mtime, s.st_size, spath);
} }
} }
closedir(dir_p); closedir(dir_p);
} }
#endif #endif
} }
void COM_ListAllFiles(void *ctx, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize, searchpath_t *spath))
{
searchpath_t *search;
if (*pattern == '/' || strchr(pattern, ':') //block absolute paths
|| strchr(pattern, '\\') //block unportable paths (also ones that mess up other checks)
|| strstr(pattern, "./")) //block evil relative paths (any kind)
{
Con_Printf("Blocking absolute/non-portable/dodgy search pattern: %s\n", pattern);
return;
}
//don't add the same pak twice.
for (search = com_searchpaths; search; search = search->next)
{
if (search->pack)
{
pack_t *pak = search->pack;
int i;
for (i = 0; i < pak->numfiles; i++)
{
if (wildcmp(pattern, pak->files[i].name))
cb(ctx, pak->files[i].name, pak->mtime, pak->files[i].filelen, search);
}
}
else
{
COM_ListFiles(ctx, search, pattern, cb);
}
}
}
static qboolean COM_AddPackage(searchpath_t *basepath, const char *pakfile) static qboolean COM_AddPackage(searchpath_t *basepath, const char *pakfile)
{ {
@ -2347,6 +2425,12 @@ static qboolean COM_AddPackage(searchpath_t *basepath, const char *pakfile)
if (!pak) if (!pak)
return false; return false;
{
struct stat s;
if (stat(pakfile, &s) >= 0)
pak->mtime = s.st_mtime;
}
search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
search->path_id = basepath->path_id; search->path_id = basepath->path_id;
search->pack = pak; search->pack = pak;

View file

@ -141,6 +141,7 @@ int Q_strncmp (const char *s1, const char *s2, int count);
int Q_atoi (const char *str); int Q_atoi (const char *str);
float Q_atof (const char *str); float Q_atof (const char *str);
void Q_ftoa(char *str, float in); void Q_ftoa(char *str, float in);
int wildcmp(const char *wild, const char *string);
#include "strl_fn.h" #include "strl_fn.h"
@ -221,6 +222,7 @@ typedef struct pack_s
char filename[MAX_OSPATH]; char filename[MAX_OSPATH];
int handle; int handle;
int numfiles; int numfiles;
time_t mtime;
packfile_t *files; packfile_t *files;
} pack_t; } pack_t;
@ -244,6 +246,7 @@ extern char com_basedir[MAX_OSPATH];
extern char com_gamedir[MAX_OSPATH]; extern char com_gamedir[MAX_OSPATH];
extern int file_from_pak; // global indicating that file came from a pak extern int file_from_pak; // global indicating that file came from a pak
void COM_ListAllFiles(void *ctx, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize, searchpath_t *spath));
const char *COM_GetGameNames(qboolean full); const char *COM_GetGameNames(qboolean full);
qboolean COM_GameDirMatches(const char *tdirs); qboolean COM_GameDirMatches(const char *tdirs);

View file

@ -2239,6 +2239,12 @@ static void PF_cvar_string(void)
q_strlcpy(temp, var->string, STRINGTEMP_LENGTH); q_strlcpy(temp, var->string, STRINGTEMP_LENGTH);
G_INT(OFS_RETURN) = PR_SetEngineString(temp); G_INT(OFS_RETURN) = PR_SetEngineString(temp);
} }
else if (!strcmp(name, "game"))
{ //game looks like a cvar in most other respects (and is a cvar in fte). let cvar_string work on it as a way to find out the current gamedir.
char *temp = PR_GetTempString();
q_strlcpy(temp, COM_GetGameNames(true), STRINGTEMP_LENGTH);
G_INT(OFS_RETURN) = PR_SetEngineString(temp);
}
else else
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
} }
@ -2905,14 +2911,16 @@ static struct filesearch_s
qcvm_t *owner; qcvm_t *owner;
size_t numfiles; size_t numfiles;
size_t maxfiles; size_t maxfiles;
unsigned int flags;
struct struct
{ {
char name[MAX_QPATH]; char name[MAX_QPATH];
time_t mtime; time_t mtime;
size_t fsize; size_t fsize;
searchpath_t *spath;
} *file; } *file;
} searches[16]; } searches[16];
static qboolean PR_Search_AddFile(void *ctx, const char *fname, time_t mtime, size_t fsize) static qboolean PR_Search_AddFile(void *ctx, const char *fname, time_t mtime, size_t fsize, searchpath_t *spath)
{ {
struct filesearch_s *c = ctx; struct filesearch_s *c = ctx;
if (c->numfiles == c->maxfiles) if (c->numfiles == c->maxfiles)
@ -2923,10 +2931,10 @@ static qboolean PR_Search_AddFile(void *ctx, const char *fname, time_t mtime, si
q_strlcpy(c->file[c->numfiles].name, fname, sizeof(c->file[c->numfiles].name)); q_strlcpy(c->file[c->numfiles].name, fname, sizeof(c->file[c->numfiles].name));
c->file[c->numfiles].mtime = mtime; c->file[c->numfiles].mtime = mtime;
c->file[c->numfiles].fsize = fsize; c->file[c->numfiles].fsize = fsize;
c->file[c->numfiles].spath = spath;
c->numfiles++; c->numfiles++;
return true; return true;
} }
void COM_ListFiles(void *ctx, const char *gamedir, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize));
static void PF_search_shutdown(void) static void PF_search_shutdown(void)
{ {
size_t i; size_t i;
@ -2947,14 +2955,16 @@ static void PF_search_begin(void)
{ {
size_t i; size_t i;
const char *pattern = G_STRING(OFS_PARM0); const char *pattern = G_STRING(OFS_PARM0);
// qboolean caseinsensitive = !!G_FLOAT(OFS_PARM0); unsigned int flags = G_FLOAT(OFS_PARM1);
// qboolaen quiet = !!G_FLOAT(OFS_PARM0); // qboolaen quiet = !!G_FLOAT(OFS_PARM2);
// const char *pkgfilter = G_STRING(OFS_PARM3);
for (i = 0; i < countof(searches); i++) for (i = 0; i < countof(searches); i++)
{ {
if (!searches[i].owner) if (!searches[i].owner)
{ {
COM_ListFiles(&searches[i], com_gamedir, pattern, PR_Search_AddFile); searches[i].flags = flags;
COM_ListAllFiles(&searches[i], pattern, PR_Search_AddFile);
if (!searches[i].numfiles) if (!searches[i].numfiles)
break; break;
searches[i].owner = qcvm; searches[i].owner = qcvm;
@ -3009,7 +3019,7 @@ static void PF_search_getfilesize(void)
} }
static void PF_search_getfilemtime(void) static void PF_search_getfilemtime(void)
{ {
char *ret = PR_GetTempString(); char *ret;
size_t handle = G_FLOAT(OFS_PARM0); size_t handle = G_FLOAT(OFS_PARM0);
size_t index = G_FLOAT(OFS_PARM1); size_t index = G_FLOAT(OFS_PARM1);
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
@ -3018,9 +3028,59 @@ static void PF_search_getfilemtime(void)
if (index < 0 || index >= searches[handle].numfiles) if (index < 0 || index >= searches[handle].numfiles)
return; //erk return; //erk
ret = PR_GetTempString();
strftime(ret, STRINGTEMP_LENGTH, "%Y-%m-%d %H:%M:%S", localtime(&searches[handle].file[index].mtime)); strftime(ret, STRINGTEMP_LENGTH, "%Y-%m-%d %H:%M:%S", localtime(&searches[handle].file[index].mtime));
G_INT(OFS_RETURN) = PR_SetEngineString(ret); G_INT(OFS_RETURN) = PR_SetEngineString(ret);
} }
static void PF_search_getpackagename(void)
{
searchpath_t *spath;
// char *ret;
size_t handle = G_FLOAT(OFS_PARM0);
size_t index = G_FLOAT(OFS_PARM1);
G_INT(OFS_RETURN) = 0;
if (handle < 0 || handle >= countof(searches))
return; //erk
if (index < 0 || index >= searches[handle].numfiles)
return; //erk
for (spath = com_searchpaths; spath; spath = spath->next)
if (spath == searches[handle].file[index].spath)
break;
if (spath)
{
if (searches[handle].flags & 2)
{ //gamedir/packagename. not necessarily fopenable.
if (spath->pack)
{
const char *pathname = spath->pack->filename;
const char *last = pathname, *last2 = "";
while (*pathname)
{
if (*pathname == '/')
{
last2 = last;
last = pathname + 1;
}
pathname++;
}
G_INT(OFS_RETURN) = PR_MakeTempString(last2);
}
else
G_INT(OFS_RETURN) = PR_MakeTempString(COM_SkipPath(spath->filename));
}
else
{ //like whichpack thus like frik_file. which sucks.
if (spath->pack)
G_INT(OFS_RETURN) = PR_MakeTempString(COM_SkipPath(spath->pack->filename));
else
G_INT(OFS_RETURN) = 0;
}
}
else
G_INT(OFS_RETURN) = 0; //no idea where it came from. sorry.
}
static void PF_whichpack(void) static void PF_whichpack(void)
{ {
@ -3419,43 +3479,6 @@ static void PF_bufstr_free(void)
strbuflist[bufno].strings[index] = NULL; strbuflist[bufno].strings[index] = NULL;
} }
static int wildcmp(const char *wild, const char *string)
{ //case-insensitive string compare with wildcards. returns true for a match.
while (*string)
{
if (*wild == '*')
{
if (*string == '/' || *string == '\\')
{
//* terminates if we get a match on the char following it, or if its a \ or / char
wild++;
continue;
}
if (wildcmp(wild+1, string))
return true;
string++;
}
else if ((q_tolower(*wild) == q_tolower(*string)) || (*wild == '?'))
{
//this char matches
wild++;
string++;
}
else
{
//failure
return false;
}
}
while (*wild == '*')
{
wild++;
}
return !*wild;
}
static void PF_buf_cvarlist(void) static void PF_buf_cvarlist(void)
{ {
size_t bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE; size_t bufno = G_FLOAT(OFS_PARM0)-BUFSTRBASE;
@ -6216,6 +6239,7 @@ static struct
{"search_getfilename",PF_search_getfilename,PF_search_getfilename,447,PF_search_getfilename,77, "string(searchhandle handle, float num)", "Retrieves name of one of the files that was found by the initial search."}, {"search_getfilename",PF_search_getfilename,PF_search_getfilename,447,PF_search_getfilename,77, "string(searchhandle handle, float num)", "Retrieves name of one of the files that was found by the initial search."},
{"search_getfilesize",PF_search_getfilesize,PF_search_getfilesize,0,PF_search_getfilesize,0, "float(searchhandle handle, float num)", "Retrieves the size of one of the files that was found by the initial search."}, {"search_getfilesize",PF_search_getfilesize,PF_search_getfilesize,0,PF_search_getfilesize,0, "float(searchhandle handle, float num)", "Retrieves the size of one of the files that was found by the initial search."},
{"search_getfilemtime",PF_search_getfilemtime,PF_search_getfilemtime,0,PF_search_getfilemtime,0, "string(searchhandle handle, float num)", "Retrieves modification time of one of the files in %Y-%m-%d %H:%M:%S format."}, {"search_getfilemtime",PF_search_getfilemtime,PF_search_getfilemtime,0,PF_search_getfilemtime,0, "string(searchhandle handle, float num)", "Retrieves modification time of one of the files in %Y-%m-%d %H:%M:%S format."},
{"search_getpackagename",PF_search_getpackagename,PF_search_getpackagename,0,PF_search_getpackagename,0, "string(searchhandle handle, float num)", "Retrieves the name of the package the file was found inside."},
{"cvar_string", PF_cvar_string, PF_cvar_string, 448, PF_cvar_string,71, "string(string cvarname)"},//DP_QC_CVAR_STRING {"cvar_string", PF_cvar_string, PF_cvar_string, 448, PF_cvar_string,71, "string(string cvarname)"},//DP_QC_CVAR_STRING
{"findflags", PF_findflags, PF_findflags, 449, PF_findflags,0, "entity(entity start, .float fld, float match)"},//DP_QC_FINDFLAGS {"findflags", PF_findflags, PF_findflags, 449, PF_findflags,0, "entity(entity start, .float fld, float match)"},//DP_QC_FINDFLAGS
{"findchainflags", PF_findchainflags, PF_findchainflags, 450, PF_NoMenu, "entity(.float fld, float match)"},//DP_QC_FINDCHAINFLAGS {"findchainflags", PF_findchainflags, PF_findchainflags, 450, PF_NoMenu, "entity(.float fld, float match)"},//DP_QC_FINDCHAINFLAGS