gzdoom-last-svn/src/cmdlib.cpp
Christoph Oelckers 0ce82b2979 Update to ZDoom r1585:
- Added ACS GetChar function.
- Added Gez's submission for polyobjects being able to crush corpses but made
  it an explicit MAPINFO option only.
- Changed APlayerPawn::DamageFade to a PalEntry from 3 floats.
- Removed #pragma warnings from cmdlib.h and fixed the places where they were 
  still triggered.
  These #pragmas were responsible for >90% of the GCC warnings that were not
  listed in VC++.
- Fixed one bug in the process: DSeqNode::m_Atten was never adjusted when the
  parameter handling of the sound functions for attenuation was changed.
  Changed m_Atten to a float and fixed the SNDSEQ parser to set proper values. 
  Also added the option to specify attenuation with direct values in addition 
  to the predefined names.
- fixed a few Heretic actors:
  * The pod generator's attacksound was wrong
  * The teleglitter generators need different flags if they are supposed to work 
    with z-aware spawning of the glitter.
  * The knight's axes need the THRUGHOST flag.
- Fixed non-POD passing in G_BuildSaveName() and other things GCC warned
  about.
- Added support for imploded zips.
- Fixed: Some missile spawning functions ignored the FastSpeed setting.
- Fixed: P_CheckSwitchRange tried to access a line's backsector without
  checking if it is valid.
- Fixed: Fast projectile could not be frozen by the Time freezer.
- Added several new ACS functions: GetActorMomX/Y/Z, GetActorViewHeight,
  SetActivator, SetActivatorToTarget.
- Added Species property for actors and separated Hexen's Demon1 and Demon2
  into different species.
- Added handling for UDMF user keys.
- Added support for ACS functions that can be defined without recompiling ACC.
- Fixed: The short lump name for embedded files must be cleared so that they
  are not found by a normal lump search.
- Added AProp_Notarget actor property.
- Fixed: TraceBleed was missing a NULL pointer check,
- Fixed: P_RandomChaseDir could crash for friendly monsters that belong to
  a player which left the game.
- Changed A_PodGrow so that it plays the generator's attack sound instead of
  "misc/podgrow".
- Added transference of a select few flags from PowerProtection to its owner.
- Added actor type parameters to A_PodPain() and A_MakePod().
- The savegame path is now passed through NicePath(), since it's user-
  specifiable.
- Added save_dir cvar. When non-empty, it controls where savegames go.
- SBARINFO update:
  * Added the ability to center things with fullscreenoffsets enabled.  Due
    to some limitations the syntax is [-]<integer> [+ center].
  * Fixed: the translucent flag on drawinventorybar didn't work quite right.
  * Fixed: Extremely minor inaccuracy in the Doom SBarInfo code.  The
    fullscreen inventory bar wasn't scaled correctly.
- fixed: The CHECKSWITCHRANGE line flag was ignored for one sided lines.
- Added more compatibility settings, submitted by Gez.
- Fixed: Doom's fullscreen HUD was limited to 6 keys.
- Made 'next endgame' work again for cases where it is supposed to be
  the same as 'next endgame4'.
- GCC nitpick fix: Classes being used as template parameters may not be
  defined locally in a function. Fixed FWadFile::SetNamespace for that.
- Improved error reporting for incorrect textures in maps.
- Fixed: When music was stopped this was not set in the global music state.
- Fixed: Friendly monsters did not target enemy players in deathmatch.
- Fixed: Completely empty patches (8 0-bytes) could not be handled by the
  texture manager. They now get assigned a new FEmptyTexture object
  that is just a 1x1 pixel transparent texture.
- Fixed: Multiple namespace markers of the same type were no longer detected.
- Fixed sprite renaming.
- Maps defined with Hexen-style MAPINFOs now run their scripts in the proper
  order.
- Fixed: FWadCollection::CheckNumForName() read the lump each iteration before
  checking for the end marker. On 32-bit systems, this is -1, but on 64-bit
  systems, it is a very large integer that is highly unlikely to be in mapped
  memory.

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@325 b0f79afe-0144-0410-b225-9a4edf0717df
2009-05-15 18:02:01 +00:00

741 lines
13 KiB
C++

// cmdlib.c (mostly borrowed from the Q2 source)
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#endif
#include "doomtype.h"
#include "cmdlib.h"
#include "i_system.h"
#include "v_text.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.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)
*/
FString progdir;
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 (const char *hex)
{
const 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 (const 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 (const 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 *buffer, size_t buffsize, const GUID &guid)
{
mysnprintf (buffer, buffsize, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
(uint32)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
const 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 */
/* */
/************************************************************************/
#ifdef _WIN32
void DoCreatePath(const char * fn)
{
char drive[_MAX_DRIVE];
char path[PATH_MAX];
char p[PATH_MAX];
int i;
_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);
_mkdir(p);
}
void CreatePath(const char * fn)
{
char name[PATH_MAX];
char c = fn[strlen(fn)-1];
if (c!='\\' && c!='/')
{
mysnprintf(name, countof(name), "%s/", fn);
DoCreatePath(name);
}
else DoCreatePath(fn);
}
#else
void CreatePath(const char *fn)
{
char *copy, *p;
if (fn[0] == '/' && fn[1] == '\0')
{
return;
}
p = copy = strdup(fn);
do
{
p = strchr(p + 1, '/');
if (p != NULL)
{
*p = '\0';
}
printf("%s\n", copy);
if (mkdir(copy, 0755) == -1)
{ // failed
return;
}
if (p != NULL)
{
*p = '/';
}
} while (p);
free(copy);
}
#endif
// [RH] Replaces the escape sequences in a string with actual escaped characters.
// This operation is done in-place. The result is the new length of the string.
int strbin (char *str)
{
char *start = str;
char *p = str, c;
int i;
while ( (c = *p++) ) {
if (c != '\\') {
*str++ = c;
} else {
switch (*p) {
case 'a':
*str++ = '\a';
break;
case 'b':
*str++ = '\b';
break;
case 'c':
*str++ = '\034'; // TEXTCOLOR_ESCAPE
break;
case 'f':
*str++ = '\f';
break;
case 'n':
*str++ = '\n';
break;
case 't':
*str++ = '\t';
break;
case 'r':
*str++ = '\r';
break;
case 'v':
*str++ = '\v';
break;
case '?':
*str++ = '\?';
break;
case '\n':
break;
case 'x':
case 'X':
c = 0;
p++;
for (i = 0; i < 2; i++) {
c <<= 4;
if (*p >= '0' && *p <= '9')
c += *p-'0';
else if (*p >= 'a' && *p <= 'f')
c += 10 + *p-'a';
else if (*p >= 'A' && *p <= 'F')
c += 10 + *p-'A';
else
break;
p++;
}
*str++ = c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
break;
p++;
}
*str++ = c;
break;
default:
*str++ = *p;
break;
}
p++;
}
}
*str = 0;
return int(str - start);
}
// [RH] Replaces the escape sequences in a string with actual escaped characters.
// This operation is done in-place. The result is the new length of the string.
FString strbin1 (const char *start)
{
FString result;
const char *p = start;
char c;
int i;
while ( (c = *p++) ) {
if (c != '\\') {
result << c;
} else {
switch (*p) {
case 'a':
result << '\a';
break;
case 'b':
result << '\b';
break;
case 'c':
result << '\034'; // TEXTCOLOR_ESCAPE
break;
case 'f':
result << '\f';
break;
case 'n':
result << '\n';
break;
case 't':
result << '\t';
break;
case 'r':
result << '\r';
break;
case 'v':
result << '\v';
break;
case '?':
result << '\?';
break;
case '\n':
break;
case 'x':
case 'X':
c = 0;
p++;
for (i = 0; i < 2; i++) {
c <<= 4;
if (*p >= '0' && *p <= '9')
c += *p-'0';
else if (*p >= 'a' && *p <= 'f')
c += 10 + *p-'a';
else if (*p >= 'A' && *p <= 'F')
c += 10 + *p-'A';
else
break;
p++;
}
result << c;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
break;
p++;
}
result << c;
break;
default:
result << *p;
break;
}
p++;
}
}
return result;
}
//==========================================================================
//
// CleanseString
//
// Does some mild sanity checking on a string: If it ends with an incomplete
// color escape, the escape is removed.
//
//==========================================================================
void CleanseString(char *str)
{
char *escape = strrchr(str, TEXTCOLOR_ESCAPE);
if (escape != NULL)
{
if (escape[1] == '\0')
{
*escape = '\0';
}
else if (escape[1] == '[')
{
char *close = strchr(escape + 2, ']');
if (close == NULL)
{
*escape = '\0';
}
}
}
}
//==========================================================================
//
// ExpandEnvVars
//
// Expands environment variable references in a string. Intended primarily
// for use with IWAD search paths in config files.
//
//==========================================================================
FString ExpandEnvVars(const char *searchpathstring)
{
static const char envvarnamechars[] =
"01234567890"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
"abcdefghijklmnopqrstuvwxyz";
if (searchpathstring == NULL)
return FString("");
const char *dollar = strchr(searchpathstring, '$');
if (dollar == NULL)
{
return FString(searchpathstring);
}
const char *nextchars = searchpathstring;
FString out = FString(searchpathstring, dollar - searchpathstring);
while ( (dollar != NULL) && (*nextchars != 0) )
{
size_t length = strspn(dollar + 1, envvarnamechars);
if (length != 0)
{
FString varname = FString(dollar + 1, length);
if (stricmp(varname, "progdir") == 0)
{
out += progdir;
}
else
{
char *varvalue = getenv(varname);
if ( (varvalue != NULL) && (strlen(varvalue) != 0) )
{
out += varvalue;
}
}
}
else
{
out += '$';
}
nextchars = dollar + length + 1;
dollar = strchr(nextchars, '$');
if (dollar != NULL)
{
out += FString(nextchars, dollar - nextchars);
}
}
if (*nextchars != 0)
{
out += nextchars;
}
return out;
}
//==========================================================================
//
// NicePath
//
// Handles paths with leading ~ characters on Unix as well as environment
// variable substitution. On Windows, this is identical to ExpandEnvVars.
//
//==========================================================================
FString NicePath(const char *path)
{
#ifdef _WIN32
return ExpandEnvVars(path);
#else
if (path == NULL || *path == '\0')
{
return FString("");
}
if (*path != '~')
{
return ExpandEnvVars(path);
}
passwd *pwstruct;
const char *slash;
if (path[1] == '/' || path[1] == '\0')
{ // Get my home directory
pwstruct = getpwuid(getuid());
slash = path + 1;
}
else
{ // Get somebody else's home directory
slash = strchr(path, '/');
if (slash == NULL)
{
slash = path + strlen(path);
}
FString who(path, slash - path);
pwstruct = getpwnam(who);
}
if (pwstruct == NULL)
{
return ExpandEnvVars(path);
}
FString where(pwstruct->pw_dir);
if (*slash != '\0')
{
where += ExpandEnvVars(slash);
}
return where;
#endif
}