SubString.h
// SubString.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2005
#pragma once
#ifndef Ceda_cxUtils_SubString_H
#define Ceda_cxUtils_SubString_H
#include "Hex.h"
#include "xstring.h"
#include "BasicSubString.h"
#ifdef _MSC_VER
// struct 'X' needs to have dll-interface to be used by clients of class 'Y'
#pragma warning(disable:4251)
#endif
namespace ceda
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// SubString8, SubString16
typedef BasicSubString<char8> SubString8;
typedef BasicSubString<char16> SubString16;
typedef BasicReversedSubString<char8> ReversedSubString8;
typedef BasicReversedSubString<char16> ReversedSubString16;
// Compare two substrings lexicographically. Similar in functionality to strcmp(const char*, const char*)
cxUtils_API int strcmp(SubString8 s1, SubString8 s2);
cxUtils_API int strcmp(SubString8 s1, const char8* s2);
cxUtils_API int strcmp(SubString16 s1, SubString16 s2);
cxUtils_API int strcmp(SubString16 s1, const char16* s2);
// string comparison
cxUtils_API bool operator==(SubString8 s1, SubString8 s2);
inline bool operator!=(SubString8 s1, SubString8 s2) { return !(s1 == s2); }
inline bool operator<(SubString8 s1, SubString8 s2) { return strcmp(s1,s2) < 0; }
inline bool operator<=(SubString8 s1, SubString8 s2) { return strcmp(s1,s2) <= 0; }
inline bool operator>(SubString8 s1, SubString8 s2) { return strcmp(s1,s2) > 0; }
inline bool operator>=(SubString8 s1, SubString8 s2) { return strcmp(s1,s2) >= 0; }
inline bool operator==(SubString8 s1, const char8* s2) { return strcmp(s1,s2) == 0; }
inline bool operator!=(SubString8 s1, const char8* s2) { return strcmp(s1,s2) != 0; }
cxUtils_API bool operator==(SubString16 s1, SubString16 s2);
inline bool operator!=(SubString16 s1, SubString16 s2) { return !(s1 == s2); }
inline bool operator<(SubString16 s1, SubString16 s2) { return strcmp(s1,s2) < 0; }
inline bool operator<=(SubString16 s1, SubString16 s2) { return strcmp(s1,s2) <= 0; }
inline bool operator>(SubString16 s1, SubString16 s2) { return strcmp(s1,s2) > 0; }
inline bool operator>=(SubString16 s1, SubString16 s2) { return strcmp(s1,s2) >= 0; }
inline bool operator==(SubString16 s1, const char16* s2) { return strcmp(s1,s2) == 0; }
inline bool operator!=(SubString16 s1, const char16* s2) { return strcmp(s1,s2) != 0; }
// Count the number of lines of text by scanning the sub string for line feeds. The last line
// doesn't need to end with a line feed
cxUtils_API ssize_t CountNumLinesOfText(SubString8 s);
cxUtils_API ssize_t CountNumLinesOfText(SubString16 s);
inline void Convert(string8& dst, SubString16 src) { Convert(dst, src.begin(), src.size()); }
inline void Convert(string16& dst, SubString8 src) { Convert(dst, src.begin(), src.size()); }
cxUtils_API xostream& operator<<(xostream& os, SubString8 s);
cxUtils_API xostream& operator<<(xostream& os, SubString16 s);
///////////////////////////////////////////////////////////////////////////////////////////////////
// SubString
typedef BasicSubString<xchar> SubString;
typedef BasicReversedSubString<xchar> ReversedSubString;
cxUtils_API void ScanIndentation(SubString& s, ssize_t indent, ssize_t tabSize = 4);
cxUtils_API void WriteSubStringWithAdjustedIndent(xostream& os, SubString s, ssize_t srcIndent);
// Returns pointer to start of given line (zero based), or nullptr if s doesn't contain enough lines
cxUtils_API const xchar* GetLineNumberPosition(SubString s, ssize_t lineNumber);
// Returns true if s begins with the given prefix. The comparison is case sensitive. Always returns true
// if the prefix is empty.
cxUtils_API bool CheckPrefix(SubString s, SubString prefix);
// If s starts with the given prefix then advance s past the prefix and return true
cxUtils_API bool EatPrefix(SubString& s, SubString prefix);
cxUtils_API bool CheckCaseInsensitivePrefix(SubString s, SubString prefix);
cxUtils_API bool EatCaseInsensitivePrefix(SubString& s, SubString prefix);
// Find position of the first occurence of sFind within s. Returns nullptr if not found
cxUtils_API const xchar* ForwardsFind(SubString s, SubString sFind);
// Find position of the first occurence of character c within s. Returns nullptr if not found
cxUtils_API const xchar* ForwardsFind(SubString s, xchar c);
// Find position of the last occurence of sFind within s. Returns nullptr if not found
cxUtils_API const xchar* ReverseFind(SubString s, SubString sFind);
// Find position of the last occurence of character c within s. Returns nullptr if not found
cxUtils_API const xchar* ReverseFind(SubString s, xchar c);
cxUtils_API xstring ToUpper(SubString s);
cxUtils_API xstring ToLower(SubString s);
cxUtils_API SubString GetPrefixBeforeLastDelimiter(SubString s, xchar c);
cxUtils_API SubString GetSuffixAfterLastDelimiter(SubString s, xchar c);
cxUtils_API bool CaseInsensitiveCompare(SubString s1, SubString s2);
cxUtils_API bool RemoveQuotesFromString(SubString& s);
cxUtils_API bool MapEscapeCharacter(xchar c1, xchar& c2);
cxUtils_API bool UnmapEscapeCharacter(xchar c1, xchar& c2);
cxUtils_API void WriteCharForCStyleLiteralConstants(xostream& os, xchar c);
cxUtils_API void MakeSingleQuotedLiteralChar(xchar c,xstring& t);
cxUtils_API void WriteDoubleQuotedString(xostream& os, SubString s);
cxUtils_API void MakeDoubleQuotedString(SubString s, xstring& t);
cxUtils_API ssize_t CountNumChars(SubString s, xchar c);
// Get the line number corresponding to the given position, or -1 if [s.p1, s.p2] doesn't contain pos
cxUtils_API ssize_t GetLineNumber(SubString s, const xchar* pos);
///////////////////////////////////////////////////////////////////////////////////////////////////
// HumanReadableChar
struct HumanReadableChar
{
HumanReadableChar(xchar _x = 0) : x(_x) {}
operator xchar() const { return x; }
xchar x;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// HumanReadableCharInSubString
struct HumanReadableCharInSubString
{
HumanReadableCharInSubString(SubString s) : m_s(s) {}
SubString m_s;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Scanning and tokenising
/*
Allow for iteration through whitespace delimited tokens in SubString s using the loop
while(s)
{
SubString token = ScanNextToken(s);
}
*/
cxUtils_API SubString ScanNextToken(SubString& s);
cxUtils_API void ScanWhiteSpace(SubString& s);
cxUtils_API bool ScanDigits(SubString& s);
cxUtils_API bool ScanIdentifier(SubString& s);
///////////////////////////////////////////////////////////////////////////////////////////////////
// StringX
class cxUtils_API StringX
{
cxNotCloneable(StringX)
public:
StringX() : m_capacity(0) {}
~StringX()
{
if (m_capacity)
{
delete [] (xchar*) m_subString.begin();
}
}
/*
StringX(const StringX& other) :
m_capacity(0),
m_subString(other.m_subString) // Make an alias
{
}
StringX& operator=(const StringX& other)
{
if (this != &other)
{
// Make an alias
Set(other.m_subString,false);
}
return *this;
}
*/
StringX(SubString other, bool makeIndependentCopy) :
m_capacity(0)
{
Set(other,makeIndependentCopy);
}
void Set(SubString other, bool makeIndependentCopy);
operator SubString() const { return m_subString; }
private:
SubString m_subString;
// Zero indicates that m_subString is an alias
ssize_t m_capacity;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Must be inside ceda namespace !!!
cxUtils_API xostream& operator<<(xostream& os, HumanReadableChar c);
cxUtils_API xostream& operator<<(xostream& os, HumanReadableCharInSubString s);
} // namespace ceda
#endif // include guard