gzdoom-last-svn/src/cmdlib.cpp
Christoph Oelckers b8a584f65f Update to ZDoom r1784:
- Added directory detection to the -file parameter. This obsoletes -dir, so
  that parameter is now gone.
- Removed automatic ".wad" appending from FWadCollection::InitMultipleFiles()
  since it isn't needed and prevented files without extensions from being
  loaded. D_AddFile() already takes care of adding the extension if the
  name as-given does not exist.
- Fixed: Loading single files did not print a newline in the startup text.
- Fixed: A_JumpIf(InTarget)Inventory jumped if the check amount was greater
  than the item's max amount and the item was maxed.
- Fixed: Some dmadds wads used zero-length sprites as placeholders. When you
  ran dmadds to combine it with the IWAD's sprites, they would be replaced by
  the IWAD's sprites, so when loading such wads, we should ignore those as
  valid sprites. (Thanks to entryway for finding this.) See 22ventry's
  22sprite.wad for an example.
- Replaced the use of autoconf's WORDS_BIGENDIAN with __BIG_ENDIAN__, since
  latter comes predefined by GCC.

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@433 b0f79afe-0144-0410-b225-9a4edf0717df
2009-09-02 06:19:49 +00:00

869 lines
17 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;
//==========================================================================
//
// IsSeperator
//
// Returns true if the character is a path seperator.
//
//==========================================================================
static inline bool IsSeperator (int c)
{
if (c == '/')
return true;
#ifdef WIN32
if (c == '\\' || c == ':')
return true;
#endif
return false;
}
//==========================================================================
//
// FixPathSeperator
//
// Convert backslashes to forward slashes.
//
//==========================================================================
void FixPathSeperator (char *path)
{
while (*path)
{
if (*path == '\\')
*path = '/';
path++;
}
}
//==========================================================================
//
// copystring
//
// Replacement for strdup that uses new instead of malloc.
//
//==========================================================================
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;
}
//==========================================================================
//
// ReplaceString
//
// Do not use in new code.
//
//==========================================================================
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
//
// Returns true if the given path exists and is a readable file.
//
//==========================================================================
bool FileExists (const char *filename)
{
FILE *f;
// [RH] Empty filenames are never there
if (filename == NULL || *filename == 0)
return false;
f = fopen (filename, "r");
if (!f)
return false;
fclose (f);
return true;
}
//==========================================================================
//
// DirEntryExists
//
// Returns true if the given path exists, be it a directory or a file.
//
//==========================================================================
bool DirEntryExists(const char *pathname)
{
if (pathname == NULL || *pathname == 0)
return false;
struct stat info;
return stat(pathname, &info) == 0;
}
//==========================================================================
//
// DefaultExtension -- char array version
//
// Appends the extension to a pathname if it does not already have one.
//
//==========================================================================
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);
}
//==========================================================================
//
// DefaultExtension -- FString version
//
// Appends the extension to a pathname if it does not already have one.
//
//==========================================================================
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;
}
//==========================================================================
//
// ExtractFilePath
//
// Returns the directory part of a pathname.
//
// 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);
}
//==========================================================================
//
// ExtractFileBase
//
// Returns the file part of a pathname, optionally including the extension.
//
//==========================================================================
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();
}
//==========================================================================
//
// 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;
}
//==========================================================================
//
// ParseNum
//
//==========================================================================
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);
}
//==========================================================================
//
// IsNum
//
// [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;
}
//==========================================================================
//
// CheckWildcards
//
// [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;
}
//==========================================================================
//
// FormatGUID
//
// [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]);
}
//==========================================================================
//
// myasctime
//
// [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 c = fn[strlen(fn)-1];
if (c != '\\' && c != '/')
{
FString name(fn);
name += '/';
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
//==========================================================================
//
// strbin1 -- In-place version
//
// [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);
}
//==========================================================================
//
// strbin1 -- String-creating version
//
// [RH] Replaces the escape sequences in a string with actual escaped characters.
// This operation is done in-place.
//
//==========================================================================
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
}