using duplicate DoomEdNums and will affect all attempts to spawn the
replaced actor. However, because this happens for all spawns and not just
at map load, the replacing actor must be compatible with the replaced
actor, which means that an actor can only serve as a replacement for one
of its baseclasses. For example, if you want to use a modified imp, you can
use this DECORATE:
actor MyImp : DoomImp replaces DoompImp
{
// Put changed properties here
}
- New: The IWAD dialog now remembers the last IWAD you picked and
automatically highlights it the next time you run the game. This also
applies if you check "Don't ask me this again": The IWAD selected will be
the one that gets automatically loaded, not the one located first. (Using
the -iwad parameter will not change the default IWAD.) In addition, you
can now bring the dialog up even if you disable it by holding down SHIFT
during startup.
- Changed ExtractFilePath() and ExtractFileBase() to return FStrings instead
of writing to a provided output buffer. ExtractFileBase() can also
optionally keep the file's extension in the result.
- Removed the -heapsize parameter entirely. The informational message should
no longer be needed.
- Removed -maxdemo parameter. There's no point to having it around since
the demo buffer grows automatically.
SVN r238 (trunk)
385 lines
6.5 KiB
C++
385 lines
6.5 KiB
C++
// cmdlib.c (mostly borrowed from the Q2 source)
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#include "doomtype.h"
|
|
#include "cmdlib.h"
|
|
#include "i_system.h"
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
|
|
#include "m_alloc.h"
|
|
|
|
/*
|
|
progdir will hold the path up to the game directory, including the slash
|
|
|
|
f:\quake\
|
|
/raid/quake/
|
|
|
|
gamedir will hold progdir + the game directory (id1, id2, etc)
|
|
|
|
*/
|
|
|
|
char progdir[1024];
|
|
|
|
static inline bool IsSeperator (int c)
|
|
{
|
|
if (c == '/')
|
|
return true;
|
|
#ifdef WIN32
|
|
if (c == '\\' || c == ':')
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void FixPathSeperator (char *path)
|
|
{
|
|
while (*path)
|
|
{
|
|
if (*path == '\\')
|
|
*path = '/';
|
|
path++;
|
|
}
|
|
}
|
|
|
|
char *copystring (const char *s)
|
|
{
|
|
char *b;
|
|
if (s)
|
|
{
|
|
size_t len = strlen (s) + 1;
|
|
b = new char[len];
|
|
memcpy (b, s, len);
|
|
}
|
|
else
|
|
{
|
|
b = new char[1];
|
|
b[0] = '\0';
|
|
}
|
|
return b;
|
|
}
|
|
|
|
|
|
void ReplaceString (char **ptr, const char *str)
|
|
{
|
|
if (*ptr)
|
|
{
|
|
if (*ptr == str)
|
|
return;
|
|
delete[] *ptr;
|
|
}
|
|
*ptr = copystring (str);
|
|
}
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
MISC FUNCTIONS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
/*
|
|
================
|
|
Q_filelength
|
|
================
|
|
*/
|
|
int Q_filelength (FILE *f)
|
|
{
|
|
int pos;
|
|
int end;
|
|
|
|
pos = ftell (f);
|
|
fseek (f, 0, SEEK_END);
|
|
end = ftell (f);
|
|
fseek (f, pos, SEEK_SET);
|
|
|
|
return end;
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
FileExists
|
|
==============
|
|
*/
|
|
BOOL FileExists (const char *filename)
|
|
{
|
|
FILE *f;
|
|
|
|
// [RH] Empty filenames are never there
|
|
if (*filename == 0)
|
|
return false;
|
|
|
|
f = fopen (filename, "r");
|
|
if (!f)
|
|
return false;
|
|
fclose (f);
|
|
return true;
|
|
}
|
|
|
|
void DefaultExtension (char *path, const char *extension)
|
|
{
|
|
char *src;
|
|
//
|
|
// if path doesn't have a .EXT, append extension
|
|
// (extension should include the .)
|
|
//
|
|
src = path + strlen(path) - 1;
|
|
|
|
while (src != path && !IsSeperator(*src))
|
|
{
|
|
if (*src == '.')
|
|
return; // it has an extension
|
|
src--;
|
|
}
|
|
|
|
strcat (path, extension);
|
|
}
|
|
|
|
void DefaultExtension (FString &path, const char *extension)
|
|
{
|
|
const char *src = &path[int(path.Len())-1];
|
|
|
|
while (src != &path[0] && !IsSeperator(*src))
|
|
{
|
|
if (*src == '.')
|
|
return; // it has an extension
|
|
src--;
|
|
}
|
|
|
|
path += extension;
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
Extract file parts
|
|
====================
|
|
*/
|
|
// FIXME: should include the slash, otherwise
|
|
// backing to an empty path will be wrong when appending a slash
|
|
FString ExtractFilePath (const char *path)
|
|
{
|
|
const char *src;
|
|
|
|
src = path + strlen(path) - 1;
|
|
|
|
//
|
|
// back up until a \ or the start
|
|
//
|
|
while (src != path && !IsSeperator(*(src-1)))
|
|
src--;
|
|
|
|
return FString(path, src - path);
|
|
}
|
|
|
|
FString ExtractFileBase (const char *path, bool include_extension)
|
|
{
|
|
const char *src, *dot;
|
|
|
|
src = path + strlen(path) - 1;
|
|
|
|
if (src >= path)
|
|
{
|
|
// back up until a / or the start
|
|
while (src != path && !IsSeperator(*(src-1)))
|
|
src--;
|
|
|
|
// Check for files with drive specification but no path
|
|
#if defined(_WIN32) || defined(DOS)
|
|
if (src == path && src[0] != 0)
|
|
{
|
|
if (src[1] == ':')
|
|
src += 2;
|
|
}
|
|
#endif
|
|
|
|
if (!include_extension)
|
|
{
|
|
dot = src;
|
|
while (*dot && *dot != '.')
|
|
{
|
|
dot++;
|
|
}
|
|
return FString(src, dot - src);
|
|
}
|
|
else
|
|
{
|
|
return FString(src);
|
|
}
|
|
}
|
|
return FString();
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
ParseNum / ParseHex
|
|
==============
|
|
*/
|
|
int ParseHex (char *hex)
|
|
{
|
|
char *str;
|
|
int num;
|
|
|
|
num = 0;
|
|
str = hex;
|
|
|
|
while (*str)
|
|
{
|
|
num <<= 4;
|
|
if (*str >= '0' && *str <= '9')
|
|
num += *str-'0';
|
|
else if (*str >= 'a' && *str <= 'f')
|
|
num += 10 + *str-'a';
|
|
else if (*str >= 'A' && *str <= 'F')
|
|
num += 10 + *str-'A';
|
|
else {
|
|
Printf ("Bad hex number: %s\n",hex);
|
|
return 0;
|
|
}
|
|
str++;
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
|
|
int ParseNum (char *str)
|
|
{
|
|
if (str[0] == '$')
|
|
return ParseHex (str+1);
|
|
if (str[0] == '0' && str[1] == 'x')
|
|
return ParseHex (str+2);
|
|
return atol (str);
|
|
}
|
|
|
|
|
|
// [RH] Returns true if the specified string is a valid decimal number
|
|
|
|
BOOL IsNum (char *str)
|
|
{
|
|
while (*str)
|
|
{
|
|
if (((*str < '0') || (*str > '9')) && (*str != '-'))
|
|
{
|
|
return false;
|
|
}
|
|
str++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// [RH] Checks if text matches the wildcard pattern using ? or *
|
|
|
|
bool CheckWildcards (const char *pattern, const char *text)
|
|
{
|
|
if (pattern == NULL || text == NULL)
|
|
return true;
|
|
|
|
while (*pattern)
|
|
{
|
|
if (*pattern == '*')
|
|
{
|
|
char stop = tolower (*++pattern);
|
|
while (*text && tolower(*text) != stop)
|
|
{
|
|
text++;
|
|
}
|
|
if (*text && tolower(*text) == stop)
|
|
{
|
|
if (CheckWildcards (pattern, text++))
|
|
{
|
|
return true;
|
|
}
|
|
pattern--;
|
|
}
|
|
}
|
|
else if (*pattern == '?' || tolower(*pattern) == tolower(*text))
|
|
{
|
|
pattern++;
|
|
text++;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return (*pattern | *text) == 0;
|
|
}
|
|
|
|
// [RH] Print a GUID to a text buffer using the standard format.
|
|
|
|
void FormatGUID (char *text, const GUID &guid)
|
|
{
|
|
sprintf (text, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
|
|
guid.Data1, guid.Data2, guid.Data3,
|
|
guid.Data4[0], guid.Data4[1],
|
|
guid.Data4[2], guid.Data4[3],
|
|
guid.Data4[4], guid.Data4[5],
|
|
guid.Data4[6], guid.Data4[7]);
|
|
}
|
|
|
|
// [RH] Returns the current local time as ASCII, even if it's too early
|
|
char *myasctime ()
|
|
{
|
|
time_t clock;
|
|
struct tm *lt;
|
|
|
|
time (&clock);
|
|
lt = localtime (&clock);
|
|
if (lt != NULL)
|
|
{
|
|
return asctime (lt);
|
|
}
|
|
else
|
|
{
|
|
return "Pre Jan 01 00:00:00 1970\n";
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreatePath: creates a directory including all levels necessary */
|
|
/* */
|
|
/************************************************************************/
|
|
void DoCreatePath(const char * fn)
|
|
{
|
|
#ifdef _WIN32
|
|
char drive[_MAX_DRIVE];
|
|
#endif
|
|
char path[PATH_MAX];
|
|
char p[PATH_MAX];
|
|
int i;
|
|
|
|
#ifdef _WIN32
|
|
_splitpath(fn,drive,path,NULL,NULL);
|
|
_makepath(p,drive,path,NULL,NULL);
|
|
i=(int)strlen(p);
|
|
if (p[i-1]=='/' || p[i-1]=='\\') p[i-1]=0;
|
|
if (*path) DoCreatePath(p);
|
|
CreateDirectory(p,NULL);
|
|
#else
|
|
// FIXME: write me
|
|
#endif
|
|
}
|
|
|
|
void CreatePath(const char * fn)
|
|
{
|
|
char name[PATH_MAX];
|
|
char c = fn[strlen(fn)-1];
|
|
|
|
if (c!='\\' && c!='/')
|
|
{
|
|
sprintf(name, "%s/", fn);
|
|
DoCreatePath(name);
|
|
}
|
|
else DoCreatePath(fn);
|
|
}
|