Files
Justin Marshall af56d4bfeb Added bot code.
2026-05-19 18:34:55 -07:00

1216 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);
void StripDoubleQuotes(void)
{
idStr temp = *this;
char* string = (char*)temp.c_str();
if (*string == '\"')
{
strcpy(string, string + 1);
}
if (string[strlen(string) - 1] == '\"')
{
string[strlen(string) - 1] = '\0';
}
*this = string;
}
// 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__ */