mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1198 lines
30 KiB
C++
1198 lines
30 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
|
|
|
IceTech Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifndef __STR_H__
|
|
#define __STR_H__
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Character string
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
|
|
#ifdef QUAKE4
|
|
#ifdef _XENON
|
|
class __declspec(align(16)) idVec4;
|
|
#else
|
|
class idVec4;
|
|
#endif
|
|
#else
|
|
class idVec4;
|
|
#endif
|
|
|
|
#ifndef FILE_HASH_SIZE
|
|
#define FILE_HASH_SIZE 1024
|
|
#endif
|
|
|
|
// color escape character
|
|
const int C_COLOR_ESCAPE = '^';
|
|
const int C_COLOR_DEFAULT = '0';
|
|
const int C_COLOR_RED = '1';
|
|
const int C_COLOR_GREEN = '2';
|
|
const int C_COLOR_YELLOW = '3';
|
|
const int C_COLOR_BLUE = '4';
|
|
const int C_COLOR_CYAN = '5';
|
|
const int C_COLOR_MAGENTA = '6';
|
|
const int C_COLOR_WHITE = '7';
|
|
const int C_COLOR_GRAY = '8';
|
|
const int C_COLOR_BLACK = '9';
|
|
#ifdef QUAKE4
|
|
const int C_COLOR_CONSOLE = ':';
|
|
#endif
|
|
|
|
// color escape string
|
|
#define S_COLOR_DEFAULT "^0"
|
|
#define S_COLOR_RED "^1"
|
|
#define S_COLOR_GREEN "^2"
|
|
#define S_COLOR_YELLOW "^3"
|
|
#define S_COLOR_BLUE "^4"
|
|
#define S_COLOR_CYAN "^5"
|
|
#define S_COLOR_MAGENTA "^6"
|
|
#define S_COLOR_WHITE "^7"
|
|
#define S_COLOR_GRAY "^8"
|
|
#define S_COLOR_BLACK "^9"
|
|
#ifdef QUAKE4
|
|
#define S_COLOR_CONSOLE "^:"
|
|
#define S_COLOR_MARINE "^c683"
|
|
#define S_COLOR_STROGG "^c950"
|
|
#define S_COLOR_ALERT "^c920"
|
|
#define I_VOICE_ENABLED "^ivce"
|
|
#define I_VOICE_DISABLED "^ivcd"
|
|
#define I_FRIEND_ENABLED "^ifde"
|
|
#define I_FRIEND_DISABLED "^ifdd"
|
|
#define I_FLAG_MARINE "^iflm"
|
|
#define I_FLAG_STROGG "^ifls"
|
|
#define I_READY "^iyrd"
|
|
#define I_NOT_READY "^inrd"
|
|
#define I_SERVER_DEDICATED "^ids0"
|
|
#define I_SERVER_DEDICATED_PB "^idsp"
|
|
#define I_SERVER_LOCKED "^isl0"
|
|
#define I_SERVER_FAVORITE "^isf0"
|
|
const int VA_BUF_LEN = 16384;
|
|
const int VA_NUM_BUFS = 8;
|
|
#endif
|
|
|
|
// make idStr a multiple of 16 bytes long
|
|
// don't make too large to keep memory requirements to a minimum
|
|
const int STR_ALLOC_BASE = 20;
|
|
const int STR_ALLOC_GRAN = 32;
|
|
|
|
typedef enum {
|
|
MEASURE_SIZE = 0,
|
|
MEASURE_BANDWIDTH
|
|
} Measure_t;
|
|
|
|
#ifdef QUAKE4
|
|
// Raven string escape codes
|
|
#define S_ESCAPE_UNKNOWN BIT(0)
|
|
#define S_ESCAPE_COLOR BIT(1)
|
|
#define S_ESCAPE_COLORINDEX BIT(2)
|
|
#define S_ESCAPE_ICON BIT(3)
|
|
#define S_ESCAPE_COMMAND BIT(4)
|
|
#define S_ESCAPE_ALL ( S_ESCAPE_COLOR | S_ESCAPE_COLORINDEX | S_ESCAPE_ICON | S_ESCAPE_COMMAND )
|
|
#endif
|
|
|
|
class idStr {
|
|
|
|
public:
|
|
idStr(void);
|
|
idStr(const idStr& text);
|
|
idStr(const idStr& text, int start, int end);
|
|
idStr(const char* text);
|
|
idStr(const char* text, int start, int end);
|
|
explicit idStr(const bool b);
|
|
explicit idStr(const char c);
|
|
explicit idStr(const int i);
|
|
explicit idStr(const unsigned u);
|
|
explicit idStr(const float f);
|
|
~idStr(void);
|
|
|
|
size_t Size(void) const;
|
|
const char* c_str(void) const;
|
|
operator const char* (void) const;
|
|
operator const char* (void);
|
|
|
|
char operator[](int index) const;
|
|
char& operator[](int index);
|
|
|
|
void operator=(const idStr& text);
|
|
void operator=(const char* text);
|
|
|
|
friend idStr operator+(const idStr& a, const idStr& b);
|
|
friend idStr operator+(const idStr& a, const char* b);
|
|
friend idStr operator+(const char* a, const idStr& b);
|
|
|
|
friend idStr operator+(const idStr& a, const float b);
|
|
friend idStr operator+(const idStr& a, const int b);
|
|
friend idStr operator+(const idStr& a, const unsigned b);
|
|
friend idStr operator+(const idStr& a, const bool b);
|
|
friend idStr operator+(const idStr& a, const char b);
|
|
|
|
idStr& operator+=(const idStr& a);
|
|
idStr& operator+=(const char* a);
|
|
idStr& operator+=(const float a);
|
|
idStr& operator+=(const char a);
|
|
idStr& operator+=(const int a);
|
|
idStr& operator+=(const unsigned a);
|
|
idStr& operator+=(const bool a);
|
|
|
|
// case sensitive compare
|
|
friend bool operator==(const idStr& a, const idStr& b);
|
|
friend bool operator==(const idStr& a, const char* b);
|
|
friend bool operator==(const char* a, const idStr& b);
|
|
|
|
// case sensitive compare
|
|
friend bool operator!=(const idStr& a, const idStr& b);
|
|
friend bool operator!=(const idStr& a, const char* b);
|
|
friend bool operator!=(const char* a, const idStr& b);
|
|
|
|
// case sensitive compare
|
|
int Cmp(const char* text) const;
|
|
int Cmpn(const char* text, int n) const;
|
|
int CmpPrefix(const char* text) const;
|
|
|
|
// case insensitive compare
|
|
int Icmp(const char* text) const;
|
|
int Icmpn(const char* text, int n) const;
|
|
int IcmpPrefix(const char* text) const;
|
|
|
|
// case insensitive compare ignoring color
|
|
int IcmpNoColor(const char* text) const;
|
|
#ifdef QUAKE4
|
|
int IcmpNoEscape(const char* text) const;
|
|
#endif
|
|
|
|
// compares paths and makes sure folders come first
|
|
int IcmpPath(const char* text) const;
|
|
int IcmpnPath(const char* text, int n) const;
|
|
int IcmpPrefixPath(const char* text) const;
|
|
|
|
int Length(void) const;
|
|
int Allocated(void) const;
|
|
void Empty(void);
|
|
bool IsEmpty(void) const;
|
|
void Clear(void);
|
|
void Append(const char a);
|
|
void Append(const idStr& text);
|
|
void Append(const char* text);
|
|
void Append(const char* text, int len);
|
|
void Insert(const char a, int index);
|
|
void Insert(const char* text, int index);
|
|
void ToLower(void);
|
|
void ToUpper(void);
|
|
bool IsNumeric(void) const;
|
|
bool IsColor(void) const;
|
|
bool HasLower(void) const;
|
|
bool HasUpper(void) const;
|
|
int LengthWithoutColors(void) const;
|
|
idStr& RemoveColors(void);
|
|
#ifdef QUAKE4
|
|
int IsEscape(int* type = NULL) const;
|
|
int LengthWithoutEscapes(void) const;
|
|
idStr& RemoveEscapes(int escapes = S_ESCAPE_ALL);
|
|
#endif
|
|
void CapLength(int);
|
|
void Fill(const char ch, int newlen);
|
|
|
|
int Find(const char c, int start = 0, int end = -1) const;
|
|
int Find(const char* text, bool casesensitive = true, int start = 0, int end = -1) const;
|
|
bool Filter(const char* filter, bool casesensitive = true) const;
|
|
int Last(const char c) const; // return the index to the last occurance of 'c', returns -1 if not found
|
|
const char* Left(int len, idStr& result) const; // store the leftmost 'len' characters in the result
|
|
const char* Right(int len, idStr& result) const; // store the rightmost 'len' characters in the result
|
|
const char* Mid(int start, int len, idStr& result) const; // store 'len' characters starting at 'start' in result
|
|
idStr Left(int len) const; // return the leftmost 'len' characters
|
|
idStr Right(int len) const; // return the rightmost 'len' characters
|
|
idStr Mid(int start, int len) const; // return 'len' characters starting at 'start'
|
|
void StripLeading(const char c); // strip char from front as many times as the char occurs
|
|
void StripLeading(const char* string); // strip string from front as many times as the string occurs
|
|
bool StripLeadingOnce(const char* string); // strip string from front just once if it occurs
|
|
void StripTrailing(const char c); // strip char from end as many times as the char occurs
|
|
void StripTrailing(const char* string); // strip string from end as many times as the string occurs
|
|
bool StripTrailingOnce(const char* string); // strip string from end just once if it occurs
|
|
void Strip(const char c); // strip char from front and end as many times as the char occurs
|
|
void Strip(const char* string); // strip string from front and end as many times as the string occurs
|
|
void StripTrailingWhitespace(void); // strip trailing white space characters
|
|
#ifdef QUAKE4
|
|
void StripUntil(const char c); // strip until this character is reached or there is no string left
|
|
#endif
|
|
idStr& StripQuotes(void); // strip quotes around string
|
|
#ifdef QUAKE4
|
|
int Replace(const char* old, const char* nw);
|
|
#else
|
|
void Replace(const char* old, const char* nw);
|
|
#endif
|
|
|
|
// file name methods
|
|
int FileNameHash(void) const; // hash key for the filename (skips extension)
|
|
idStr& BackSlashesToSlashes(void); // convert slashes
|
|
#ifdef QUAKE4
|
|
idStr& SlashesToBackSlashes(void); // convert slashes
|
|
bool HasChar(const char check);
|
|
bool HasChars(const char* check);
|
|
idStr& ReplaceChar(const char from, const char to);
|
|
idStr& ReplaceChars(const char* from, const char to);
|
|
#endif
|
|
idStr& SetFileExtension(const char* extension); // set the given file extension
|
|
idStr& StripFileExtension(void); // remove any file extension
|
|
idStr& StripAbsoluteFileExtension(void); // remove any file extension looking from front (useful if there are multiple .'s)
|
|
idStr& DefaultFileExtension(const char* extension); // if there's no file extension use the default
|
|
idStr& DefaultPath(const char* basepath); // if there's no path use the default
|
|
void AppendPath(const char* text); // append a partial path
|
|
idStr& StripFilename(void); // remove the filename from a path
|
|
idStr& StripPath(void); // remove the path from the filename
|
|
void ExtractFilePath(idStr& dest) const; // copy the file path to another string
|
|
void ExtractFileName(idStr& dest) const; // copy the filename to another string
|
|
void ExtractFileBase(idStr& dest) const; // copy the filename minus the extension to another string
|
|
void ExtractFileExtension(idStr& dest) const; // copy the file extension to another string
|
|
bool CheckExtension(const char* ext);
|
|
#ifdef QUAKE4
|
|
void ScrubFileName(void); // Turns a bad file name into a good one or your money back
|
|
void MakeNameCanonical(void);
|
|
void EnsurePrintable(void);
|
|
void Split(idList<idStr>& list, const char delimiter = ',', const char groupDelimiter = '\'');
|
|
#endif
|
|
|
|
// char * methods to replace library functions
|
|
static int Length(const char* s);
|
|
static char* ToLower(char* s);
|
|
static char* ToUpper(char* s);
|
|
static bool IsNumeric(const char* s);
|
|
static bool IsColor(const char* s);
|
|
static bool HasLower(const char* s);
|
|
static bool HasUpper(const char* s);
|
|
static int LengthWithoutColors(const char* s);
|
|
static char* RemoveColors(char* s);
|
|
#ifdef QUAKE4
|
|
static int IsEscape(const char* s, int* type = NULL);
|
|
static int LengthWithoutEscapes(const char* s);
|
|
static char* RemoveEscapes(char* s, int escapes = S_ESCAPE_ALL);
|
|
#endif
|
|
static int Cmp(const char* s1, const char* s2);
|
|
static int Cmpn(const char* s1, const char* s2, int n);
|
|
static int Icmp(const char* s1, const char* s2);
|
|
static int Icmpn(const char* s1, const char* s2, int n);
|
|
static int IcmpNoColor(const char* s1, const char* s2);
|
|
#ifdef QUAKE4
|
|
static int IcmpNoEscape(const char* s1, const char* s2);
|
|
#endif
|
|
static int IcmpPath(const char* s1, const char* s2); // compares paths and makes sure folders come first
|
|
static int IcmpnPath(const char* s1, const char* s2, int n); // compares paths and makes sure folders come first
|
|
static void Append(char* dest, int size, const char* src);
|
|
static void Copynz(char* dest, const char* src, int destsize);
|
|
static int snPrintf(char* dest, int size, const char* fmt, ...) id_attribute((format(printf, 3, 4)));
|
|
static int vsnPrintf(char* dest, int size, const char* fmt, va_list argptr);
|
|
static int FindChar(const char* str, const char c, int start = 0, int end = -1);
|
|
static int FindText(const char* str, const char* text, bool casesensitive = true, int start = 0, int end = -1);
|
|
static bool Filter(const char* filter, const char* name, bool casesensitive);
|
|
static void StripMediaName(const char* name, idStr& mediaName);
|
|
static bool CheckExtension(const char* name, const char* ext);
|
|
static const char* FloatArrayToString(const float* array, const int length, const int precision);
|
|
|
|
// hash keys
|
|
static int Hash(const char* string);
|
|
static int Hash(const char* string, int length);
|
|
static int IHash(const char* string); // case insensitive
|
|
static int IHash(const char* string, int length); // case insensitive
|
|
|
|
// character methods
|
|
#ifdef QUAKE4
|
|
static char ToLower(byte c);
|
|
static char ToUpper(byte c);
|
|
static bool CharIsPrintable(byte c);
|
|
static bool CharIsLower(byte c);
|
|
static bool CharIsUpper(byte c);
|
|
static bool CharIsAlpha(byte c);
|
|
static bool CharIsNumeric(byte c);
|
|
static bool CharIsNewLine(byte c);
|
|
static bool CharIsTab(byte c);
|
|
#else
|
|
static char ToLower(char c);
|
|
static char ToUpper(char c);
|
|
static bool CharIsPrintable(int c);
|
|
static bool CharIsLower(int c);
|
|
static bool CharIsUpper(int c);
|
|
static bool CharIsAlpha(int c);
|
|
static bool CharIsNumeric(int c);
|
|
static bool CharIsNewLine(char c);
|
|
static bool CharIsTab(char c);
|
|
#endif
|
|
static int ColorIndex(int c);
|
|
static idVec4& ColorForIndex(int i);
|
|
|
|
friend int sprintf(idStr& dest, const char* fmt, ...);
|
|
friend int vsprintf(idStr& dest, const char* fmt, va_list ap);
|
|
|
|
void ReAllocate(int amount, bool keepold); // reallocate string data buffer
|
|
void FreeData(void); // free allocated string memory
|
|
|
|
// format value in the given measurement with the best unit, returns the best unit
|
|
int BestUnit(const char* format, float value, Measure_t measure);
|
|
// format value in the requested unit and measurement
|
|
void SetUnit(const char* format, float value, int unit, Measure_t measure);
|
|
|
|
static void InitMemory(void);
|
|
static void ShutdownMemory(void);
|
|
static void PurgeMemory(void);
|
|
static void ShowMemoryUsage_f(const idCmdArgs& args);
|
|
|
|
int DynamicMemoryUsed() const;
|
|
static idStr FormatNumber(int number);
|
|
#ifdef QUAKE4
|
|
static void Split(const char* source, idList<idStr>& list, const char delimiter = ',', const char groupDelimiter = '\'');
|
|
idStr GetLastColorCode(void) const;
|
|
#endif
|
|
|
|
protected:
|
|
int len;
|
|
char* data;
|
|
int alloced;
|
|
char baseBuffer[STR_ALLOC_BASE];
|
|
|
|
void Init(void); // initialize string using base buffer
|
|
void EnsureAlloced(int amount, bool keepold = true); // ensure string data buffer is large anough
|
|
|
|
#ifdef QUAKE4
|
|
public:
|
|
static const bool printableCharacter[256];
|
|
static const char upperCaseCharacter[256];
|
|
static const char lowerCaseCharacter[256];
|
|
#endif
|
|
};
|
|
|
|
char* va(const char* fmt, ...) id_attribute((format(printf, 1, 2)));
|
|
#ifdef QUAKE4
|
|
char* fe(int errorId);
|
|
#endif
|
|
|
|
|
|
ID_INLINE void idStr::EnsureAlloced(int amount, bool keepold) {
|
|
if (amount > alloced) {
|
|
ReAllocate(amount, keepold);
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idStr::Init(void) {
|
|
len = 0;
|
|
alloced = STR_ALLOC_BASE;
|
|
data = baseBuffer;
|
|
data[0] = '\0';
|
|
#if defined( ID_DEBUG_UNINITIALIZED_MEMORY ) || ( defined( QUAKE4 ) && defined( ID_DEBUG_MEMORY ) )
|
|
memset(baseBuffer, 0, sizeof(baseBuffer));
|
|
#endif
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(void) {
|
|
Init();
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const idStr& text) {
|
|
int l;
|
|
|
|
Init();
|
|
l = text.Length();
|
|
EnsureAlloced(l + 1);
|
|
strcpy(data, text.data);
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const idStr& text, int start, int end) {
|
|
int i;
|
|
int l;
|
|
|
|
Init();
|
|
if (end > text.Length()) {
|
|
end = text.Length();
|
|
}
|
|
if (start > text.Length()) {
|
|
start = text.Length();
|
|
}
|
|
else if (start < 0) {
|
|
start = 0;
|
|
}
|
|
|
|
l = end - start;
|
|
if (l < 0) {
|
|
l = 0;
|
|
}
|
|
|
|
EnsureAlloced(l + 1);
|
|
|
|
for (i = 0; i < l; i++) {
|
|
data[i] = text[start + i];
|
|
}
|
|
|
|
data[l] = '\0';
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const char* text) {
|
|
int l;
|
|
|
|
Init();
|
|
if (text) {
|
|
l = strlen(text);
|
|
EnsureAlloced(l + 1);
|
|
strcpy(data, text);
|
|
len = l;
|
|
}
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const char* text, int start, int end) {
|
|
int i;
|
|
int l = strlen(text);
|
|
|
|
Init();
|
|
if (end > l) {
|
|
end = l;
|
|
}
|
|
if (start > l) {
|
|
start = l;
|
|
}
|
|
else if (start < 0) {
|
|
start = 0;
|
|
}
|
|
|
|
l = end - start;
|
|
if (l < 0) {
|
|
l = 0;
|
|
}
|
|
|
|
EnsureAlloced(l + 1);
|
|
|
|
for (i = 0; i < l; i++) {
|
|
data[i] = text[start + i];
|
|
}
|
|
|
|
data[l] = '\0';
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const bool b) {
|
|
Init();
|
|
EnsureAlloced(2);
|
|
data[0] = b ? '1' : '0';
|
|
data[1] = '\0';
|
|
len = 1;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const char c) {
|
|
Init();
|
|
EnsureAlloced(2);
|
|
data[0] = c;
|
|
data[1] = '\0';
|
|
len = 1;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const int i) {
|
|
char text[64];
|
|
int l;
|
|
|
|
Init();
|
|
l = sprintf(text, "%d", i);
|
|
EnsureAlloced(l + 1);
|
|
strcpy(data, text);
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const unsigned u) {
|
|
char text[64];
|
|
int l;
|
|
|
|
Init();
|
|
l = sprintf(text, "%u", u);
|
|
EnsureAlloced(l + 1);
|
|
strcpy(data, text);
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::idStr(const float f) {
|
|
char text[64];
|
|
int l;
|
|
|
|
Init();
|
|
l = idStr::snPrintf(text, sizeof(text), "%f", f);
|
|
while (l > 0 && text[l - 1] == '0') text[--l] = '\0';
|
|
while (l > 0 && text[l - 1] == '.') text[--l] = '\0';
|
|
EnsureAlloced(l + 1);
|
|
strcpy(data, text);
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr::~idStr(void) {
|
|
FreeData();
|
|
}
|
|
|
|
ID_INLINE size_t idStr::Size(void) const {
|
|
return sizeof(*this) + Allocated();
|
|
}
|
|
|
|
ID_INLINE const char* idStr::c_str(void) const {
|
|
return data;
|
|
}
|
|
|
|
ID_INLINE idStr::operator const char* (void) {
|
|
return c_str();
|
|
}
|
|
|
|
ID_INLINE idStr::operator const char* (void) const {
|
|
return c_str();
|
|
}
|
|
|
|
ID_INLINE char idStr::operator[](int index) const {
|
|
assert((index >= 0) && (index <= len));
|
|
return data[index];
|
|
}
|
|
|
|
ID_INLINE char& idStr::operator[](int index) {
|
|
assert((index >= 0) && (index <= len));
|
|
return data[index];
|
|
}
|
|
|
|
ID_INLINE void idStr::operator=(const idStr& text) {
|
|
int l;
|
|
|
|
l = text.Length();
|
|
EnsureAlloced(l + 1, false);
|
|
memcpy(data, text.data, l);
|
|
data[l] = '\0';
|
|
len = l;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const idStr& b) {
|
|
idStr result(a);
|
|
result.Append(b);
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const char* b) {
|
|
idStr result(a);
|
|
result.Append(b);
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const char* a, const idStr& b) {
|
|
idStr result(a);
|
|
result.Append(b);
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const bool b) {
|
|
idStr result(a);
|
|
result.Append(b ? "true" : "false");
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const char b) {
|
|
idStr result(a);
|
|
result.Append(b);
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const float b) {
|
|
char text[64];
|
|
idStr result(a);
|
|
|
|
sprintf(text, "%f", b);
|
|
result.Append(text);
|
|
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const int b) {
|
|
char text[64];
|
|
idStr result(a);
|
|
|
|
sprintf(text, "%d", b);
|
|
result.Append(text);
|
|
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr operator+(const idStr& a, const unsigned b) {
|
|
char text[64];
|
|
idStr result(a);
|
|
|
|
sprintf(text, "%u", b);
|
|
result.Append(text);
|
|
|
|
return result;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const float a) {
|
|
char text[64];
|
|
|
|
sprintf(text, "%f", a);
|
|
Append(text);
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const int a) {
|
|
char text[64];
|
|
|
|
sprintf(text, "%d", a);
|
|
Append(text);
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const unsigned a) {
|
|
char text[64];
|
|
|
|
sprintf(text, "%u", a);
|
|
Append(text);
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const idStr& a) {
|
|
Append(a);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const char* a) {
|
|
Append(a);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const char a) {
|
|
Append(a);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::operator+=(const bool a) {
|
|
Append(a ? "true" : "false");
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE bool operator==(const idStr& a, const idStr& b) {
|
|
return (!idStr::Cmp(a.data, b.data));
|
|
}
|
|
|
|
ID_INLINE bool operator==(const idStr& a, const char* b) {
|
|
assert(b);
|
|
return (!idStr::Cmp(a.data, b));
|
|
}
|
|
|
|
ID_INLINE bool operator==(const char* a, const idStr& b) {
|
|
assert(a);
|
|
return (!idStr::Cmp(a, b.data));
|
|
}
|
|
|
|
ID_INLINE bool operator!=(const idStr& a, const idStr& b) {
|
|
return !(a == b);
|
|
}
|
|
|
|
ID_INLINE bool operator!=(const idStr& a, const char* b) {
|
|
return !(a == b);
|
|
}
|
|
|
|
ID_INLINE bool operator!=(const char* a, const idStr& b) {
|
|
return !(a == b);
|
|
}
|
|
|
|
ID_INLINE int idStr::Cmp(const char* text) const {
|
|
assert(text);
|
|
return idStr::Cmp(data, text);
|
|
}
|
|
|
|
ID_INLINE int idStr::Cmpn(const char* text, int n) const {
|
|
assert(text);
|
|
return idStr::Cmpn(data, text, n);
|
|
}
|
|
|
|
ID_INLINE int idStr::CmpPrefix(const char* text) const {
|
|
assert(text);
|
|
return idStr::Cmpn(data, text, strlen(text));
|
|
}
|
|
|
|
ID_INLINE int idStr::Icmp(const char* text) const {
|
|
assert(text);
|
|
return idStr::Icmp(data, text);
|
|
}
|
|
|
|
ID_INLINE int idStr::Icmpn(const char* text, int n) const {
|
|
assert(text);
|
|
return idStr::Icmpn(data, text, n);
|
|
}
|
|
|
|
ID_INLINE int idStr::IcmpPrefix(const char* text) const {
|
|
assert(text);
|
|
return idStr::Icmpn(data, text, strlen(text));
|
|
}
|
|
|
|
ID_INLINE int idStr::IcmpNoColor(const char* text) const {
|
|
assert(text);
|
|
return idStr::IcmpNoColor(data, text);
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE int idStr::IcmpNoEscape(const char* text) const {
|
|
assert(text);
|
|
return idStr::IcmpNoEscape(data, text);
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE int idStr::IcmpPath(const char* text) const {
|
|
assert(text);
|
|
return idStr::IcmpPath(data, text);
|
|
}
|
|
|
|
ID_INLINE int idStr::IcmpnPath(const char* text, int n) const {
|
|
assert(text);
|
|
return idStr::IcmpnPath(data, text, n);
|
|
}
|
|
|
|
ID_INLINE int idStr::IcmpPrefixPath(const char* text) const {
|
|
assert(text);
|
|
return idStr::IcmpnPath(data, text, strlen(text));
|
|
}
|
|
|
|
ID_INLINE int idStr::Length(void) const {
|
|
return len;
|
|
}
|
|
|
|
ID_INLINE int idStr::Allocated(void) const {
|
|
if (data != baseBuffer) {
|
|
return alloced;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idStr::Empty(void) {
|
|
EnsureAlloced(1);
|
|
data[0] = '\0';
|
|
len = 0;
|
|
}
|
|
|
|
ID_INLINE bool idStr::IsEmpty(void) const {
|
|
return (idStr::Cmp(data, "") == 0);
|
|
}
|
|
|
|
ID_INLINE void idStr::Clear(void) {
|
|
FreeData();
|
|
Init();
|
|
}
|
|
|
|
ID_INLINE void idStr::Append(const char a) {
|
|
EnsureAlloced(len + 2);
|
|
data[len] = a;
|
|
len++;
|
|
data[len] = '\0';
|
|
}
|
|
|
|
ID_INLINE void idStr::Append(const idStr& text) {
|
|
int newLen;
|
|
int i;
|
|
|
|
newLen = len + text.Length();
|
|
EnsureAlloced(newLen + 1);
|
|
for (i = 0; i < text.len; i++) {
|
|
data[len + i] = text[i];
|
|
}
|
|
len = newLen;
|
|
data[len] = '\0';
|
|
}
|
|
|
|
ID_INLINE void idStr::Append(const char* text) {
|
|
int newLen;
|
|
int i;
|
|
|
|
if (text) {
|
|
newLen = len + strlen(text);
|
|
EnsureAlloced(newLen + 1);
|
|
for (i = 0; text[i]; i++) {
|
|
data[len + i] = text[i];
|
|
}
|
|
len = newLen;
|
|
data[len] = '\0';
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idStr::Append(const char* text, int l) {
|
|
int newLen;
|
|
int i;
|
|
|
|
if (text && l) {
|
|
newLen = len + l;
|
|
EnsureAlloced(newLen + 1);
|
|
for (i = 0; text[i] && i < l; i++) {
|
|
data[len + i] = text[i];
|
|
}
|
|
len = newLen;
|
|
data[len] = '\0';
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idStr::Insert(const char a, int index) {
|
|
int i, l;
|
|
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
else if (index > len) {
|
|
index = len;
|
|
}
|
|
|
|
l = 1;
|
|
EnsureAlloced(len + l + 1);
|
|
for (i = len; i >= index; i--) {
|
|
data[i + l] = data[i];
|
|
}
|
|
data[index] = a;
|
|
len++;
|
|
}
|
|
|
|
ID_INLINE void idStr::Insert(const char* text, int index) {
|
|
int i, l;
|
|
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
else if (index > len) {
|
|
index = len;
|
|
}
|
|
|
|
l = strlen(text);
|
|
EnsureAlloced(len + l + 1);
|
|
for (i = len; i >= index; i--) {
|
|
data[i + l] = data[i];
|
|
}
|
|
for (i = 0; i < l; i++) {
|
|
data[index + i] = text[i];
|
|
}
|
|
len += l;
|
|
}
|
|
|
|
ID_INLINE void idStr::ToLower(void) {
|
|
for (int i = 0; data[i]; i++) {
|
|
#ifdef QUAKE4
|
|
data[i] = ToLower((byte)data[i]);
|
|
#else
|
|
if (CharIsUpper(data[i])) {
|
|
data[i] += ('a' - 'A');
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idStr::ToUpper(void) {
|
|
for (int i = 0; data[i]; i++) {
|
|
#ifdef QUAKE4
|
|
data[i] = ToUpper((byte)data[i]);
|
|
#else
|
|
if (CharIsLower(data[i])) {
|
|
data[i] -= ('a' - 'A');
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ID_INLINE bool idStr::IsNumeric(void) const {
|
|
return idStr::IsNumeric(data);
|
|
}
|
|
|
|
ID_INLINE bool idStr::IsColor(void) const {
|
|
return idStr::IsColor(data);
|
|
}
|
|
|
|
ID_INLINE bool idStr::HasLower(void) const {
|
|
return idStr::HasLower(data);
|
|
}
|
|
|
|
ID_INLINE bool idStr::HasUpper(void) const {
|
|
return idStr::HasUpper(data);
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::RemoveColors(void) {
|
|
idStr::RemoveColors(data);
|
|
len = Length(data);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE int idStr::LengthWithoutColors(void) const {
|
|
return idStr::LengthWithoutColors(data);
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE int idStr::IsEscape(int* type) const {
|
|
return idStr::IsEscape(data, type);
|
|
}
|
|
|
|
ID_INLINE idStr& idStr::RemoveEscapes(int escapes) {
|
|
idStr::RemoveEscapes(data, escapes);
|
|
len = Length(data);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE int idStr::LengthWithoutEscapes(void) const {
|
|
return idStr::LengthWithoutEscapes(data);
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE void idStr::CapLength(int newlen) {
|
|
if (len <= newlen) {
|
|
return;
|
|
}
|
|
data[newlen] = 0;
|
|
len = newlen;
|
|
}
|
|
|
|
ID_INLINE void idStr::Fill(const char ch, int newlen) {
|
|
EnsureAlloced(newlen + 1);
|
|
len = newlen;
|
|
memset(data, ch, len);
|
|
data[len] = 0;
|
|
}
|
|
|
|
ID_INLINE int idStr::Find(const char c, int start, int end) const {
|
|
if (end == -1) {
|
|
end = len;
|
|
}
|
|
return idStr::FindChar(data, c, start, end);
|
|
}
|
|
|
|
ID_INLINE int idStr::Find(const char* text, bool casesensitive, int start, int end) const {
|
|
if (end == -1) {
|
|
end = len;
|
|
}
|
|
return idStr::FindText(data, text, casesensitive, start, end);
|
|
}
|
|
|
|
ID_INLINE bool idStr::Filter(const char* filter, bool casesensitive) const {
|
|
return idStr::Filter(filter, data, casesensitive);
|
|
}
|
|
|
|
ID_INLINE const char* idStr::Left(int len, idStr& result) const {
|
|
return Mid(0, len, result);
|
|
}
|
|
|
|
ID_INLINE const char* idStr::Right(int len, idStr& result) const {
|
|
if (len >= Length()) {
|
|
result = *this;
|
|
return result;
|
|
}
|
|
return Mid(Length() - len, len, result);
|
|
}
|
|
|
|
ID_INLINE idStr idStr::Left(int len) const {
|
|
return Mid(0, len);
|
|
}
|
|
|
|
ID_INLINE idStr idStr::Right(int len) const {
|
|
if (len >= Length()) {
|
|
return *this;
|
|
}
|
|
return Mid(Length() - len, len);
|
|
}
|
|
|
|
ID_INLINE void idStr::Strip(const char c) {
|
|
StripLeading(c);
|
|
StripTrailing(c);
|
|
}
|
|
|
|
ID_INLINE void idStr::Strip(const char* string) {
|
|
StripLeading(string);
|
|
StripTrailing(string);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CheckExtension(const char* ext) {
|
|
return idStr::CheckExtension(data, ext);
|
|
}
|
|
|
|
ID_INLINE int idStr::Length(const char* s) {
|
|
int i;
|
|
for (i = 0; s[i]; i++) {}
|
|
return i;
|
|
}
|
|
|
|
ID_INLINE char* idStr::ToLower(char* s) {
|
|
for (int i = 0; s[i]; i++) {
|
|
#ifdef QUAKE4
|
|
s[i] = ToLower((byte)s[i]);
|
|
#else
|
|
if (CharIsUpper(s[i])) {
|
|
s[i] += ('a' - 'A');
|
|
}
|
|
#endif
|
|
}
|
|
return s;
|
|
}
|
|
|
|
ID_INLINE char* idStr::ToUpper(char* s) {
|
|
for (int i = 0; s[i]; i++) {
|
|
#ifdef QUAKE4
|
|
s[i] = ToUpper((byte)s[i]);
|
|
#else
|
|
if (CharIsLower(s[i])) {
|
|
s[i] -= ('a' - 'A');
|
|
}
|
|
#endif
|
|
}
|
|
return s;
|
|
}
|
|
|
|
ID_INLINE int idStr::Hash(const char* string) {
|
|
int i, hash = 0;
|
|
for (i = 0; *string != '\0'; i++) {
|
|
hash += (*string++) * (i + 119);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
ID_INLINE int idStr::Hash(const char* string, int length) {
|
|
int i, hash = 0;
|
|
for (i = 0; i < length; i++) {
|
|
hash += (*string++) * (i + 119);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
ID_INLINE int idStr::IHash(const char* string) {
|
|
int i, hash = 0;
|
|
for (i = 0; *string != '\0'; i++) {
|
|
hash += ToLower(*string++) * (i + 119);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
ID_INLINE int idStr::IHash(const char* string, int length) {
|
|
int i, hash = 0;
|
|
for (i = 0; i < length; i++) {
|
|
hash += ToLower(*string++) * (i + 119);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
ID_INLINE bool idStr::IsColor(const char* s) {
|
|
return (s[0] == C_COLOR_ESCAPE && s[1] != '\0' && s[1] != ' ');
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE char idStr::ToLower(byte c) {
|
|
if (lowerCaseCharacter[c]) {
|
|
return lowerCaseCharacter[c];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ID_INLINE char idStr::ToUpper(byte c) {
|
|
if (upperCaseCharacter[c]) {
|
|
return upperCaseCharacter[c];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsPrintable(byte c) {
|
|
return printableCharacter[c];
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsLower(byte c) {
|
|
return !!lowerCaseCharacter[c] && (lowerCaseCharacter[c] == c);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsUpper(byte c) {
|
|
return !!upperCaseCharacter[c] && (upperCaseCharacter[c] == c);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsAlpha(byte c) {
|
|
return !!upperCaseCharacter[c];
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsNumeric(byte c) {
|
|
return (c <= '9' && c >= '0');
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsNewLine(byte c) {
|
|
return (c == '\n' || c == '\r' || c == '\v');
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsTab(byte c) {
|
|
return (c == '\t');
|
|
}
|
|
#else
|
|
ID_INLINE char idStr::ToLower(char c) {
|
|
if (c <= 'Z' && c >= 'A') {
|
|
return (c + ('a' - 'A'));
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ID_INLINE char idStr::ToUpper(char c) {
|
|
if (c >= 'a' && c <= 'z') {
|
|
return (c - ('a' - 'A'));
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsPrintable(int c) {
|
|
return (c >= 0x20 && c <= 0x7E) || (c >= 0xA1 && c <= 0xFF);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsLower(int c) {
|
|
return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsUpper(int c) {
|
|
return (c <= 'Z' && c >= 'A') || (c >= 0xC0 && c <= 0xDF);
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsAlpha(int c) {
|
|
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
(c >= 0xC0 && c <= 0xFF));
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsNumeric(int c) {
|
|
return (c <= '9' && c >= '0');
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsNewLine(char c) {
|
|
return (c == '\n' || c == '\r' || c == '\v');
|
|
}
|
|
|
|
ID_INLINE bool idStr::CharIsTab(char c) {
|
|
return (c == '\t');
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE int idStr::ColorIndex(int c) {
|
|
return (c & 15);
|
|
}
|
|
|
|
ID_INLINE int idStr::DynamicMemoryUsed() const {
|
|
return (data == baseBuffer) ? 0 : alloced;
|
|
}
|
|
|
|
#endif /* !__STR_H__ */
|