diff options
-rw-r--r-- | gtk/ScintillaGTK.cxx | 1 | ||||
-rw-r--r-- | include/KeyWords.h | 23 | ||||
-rw-r--r-- | include/PropSet.h | 89 | ||||
-rw-r--r-- | include/WindowAccessor.h | 5 | ||||
-rw-r--r-- | src/AutoComplete.cxx | 2 | ||||
-rw-r--r-- | src/CharClassify.cxx | 34 | ||||
-rw-r--r-- | src/CharClassify.h | 14 | ||||
-rw-r--r-- | src/Document.cxx | 10 | ||||
-rw-r--r-- | src/DocumentAccessor.h | 5 | ||||
-rw-r--r-- | src/KeyWords.cxx | 186 | ||||
-rw-r--r-- | src/LexCaml.cxx | 3 | ||||
-rw-r--r-- | src/LexCmake.cxx | 1 | ||||
-rw-r--r-- | src/LexHaskell.cxx | 3 | ||||
-rw-r--r-- | src/LexInno.cxx | 1 | ||||
-rw-r--r-- | src/LexNsis.cxx | 1 | ||||
-rw-r--r-- | src/LexOthers.cxx | 1 | ||||
-rw-r--r-- | src/PropSet.cxx | 713 | ||||
-rw-r--r-- | src/ScintillaBase.cxx | 16 | ||||
-rw-r--r-- | src/ScintillaBase.h | 2 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 1 |
20 files changed, 354 insertions, 757 deletions
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 2913003ba..2a8b057a2 100644 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -26,6 +26,7 @@ #ifdef SCI_LEXER #include "SciLexer.h" #include "PropSet.h" +#include "PropSetSimple.h" #include "Accessor.h" #include "KeyWords.h" #endif diff --git a/include/KeyWords.h b/include/KeyWords.h index 6abae5945..5593b7d09 100644 --- a/include/KeyWords.h +++ b/include/KeyWords.h @@ -9,6 +9,29 @@ namespace Scintilla { #endif +/** + */ +class WordList { +public: + // Each word contains at least one character - a empty word acts as sentinel at the end. + char **words; + char *list; + int len; + bool onlyLineEnds; ///< Delimited by any white space or only line ends + bool sorted; + int starts[256]; + WordList(bool onlyLineEnds_ = false) : + words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_), + sorted(false) + {} + ~WordList() { Clear(); } + operator bool() { return len ? true : false; } + void Clear(); + void Set(const char *s); + bool InList(const char *s); + bool InListAbbreviated(const char *s, const char marker); +}; + typedef void (*LexerFunction)(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler); diff --git a/include/PropSet.h b/include/PropSet.h index 91bc7072b..bb24e2ac4 100644 --- a/include/PropSet.h +++ b/include/PropSet.h @@ -1,104 +1,25 @@ // Scintilla source code edit control /** @file PropSet.h - ** A Java style properties file module. + ** An interface to the methods needed for access to property sets inside lexers. **/ -// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org> +// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. #ifndef PROPSET_H #define PROPSET_H -#include "SString.h" - -bool EqualCaseInsensitive(const char *a, const char *b); - -bool isprefix(const char *target, const char *prefix); #ifdef SCI_NAMESPACE namespace Scintilla { #endif -struct Property { - unsigned int hash; - char *key; - char *val; - Property *next; - Property() : hash(0), key(0), val(0), next(0) {} -}; - -/** - */ -class PropSet { -protected: - enum { hashRoots=31 }; - Property *props[hashRoots]; - Property *enumnext; - int enumhash; - static unsigned int HashString(const char *s, size_t len) { - unsigned int ret = 0; - while (len--) { - ret <<= 4; - ret ^= *s; - s++; - } - return ret; - } - +class PropertyGet { public: - PropSet *superPS; - PropSet(); - ~PropSet(); - void Set(const char *key, const char *val, int lenKey=-1, int lenVal=-1); - void Set(const char *keyVal); - void Unset(const char *key, int lenKey=-1); - void SetMultiple(const char *s); - SString Get(const char *key) const; - SString GetExpanded(const char *key) const; - SString Expand(const char *withVars, int maxExpands=100) const; - int GetInt(const char *key, int defaultValue=0) const; - void Clear(); - char *ToString() const; // Caller must delete[] the return value - -private: - // copy-value semantics not implemented - PropSet(const PropSet ©); - void operator=(const PropSet &assign); + virtual char *ToString() const=0; // Caller must delete[] the return value + virtual int GetInt(const char *key, int defaultValue=0) const=0; }; -/** - */ -class WordList { -public: - // Each word contains at least one character - a empty word acts as sentinel at the end. - char **words; - char *list; - int len; - bool onlyLineEnds; ///< Delimited by any white space or only line ends - bool sorted; - int starts[256]; - WordList(bool onlyLineEnds_ = false) : - words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_), - sorted(false) - {} - ~WordList() { Clear(); } - operator bool() { return len ? true : false; } - void Clear(); - void Set(const char *s); - bool InList(const char *s); - bool InListAbbreviated(const char *s, const char marker); -}; - -inline bool IsAlphabetic(unsigned int ch) { - return ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')); -} - #ifdef SCI_NAMESPACE } #endif -#ifdef _MSC_VER -// Visual C++ doesn't like the private copy idiom for disabling -// the default copy constructor and operator=, but it's fine. -#pragma warning(disable: 4511 4512) -#endif - #endif diff --git a/include/WindowAccessor.h b/include/WindowAccessor.h index e107a0659..6f265f658 100644 --- a/include/WindowAccessor.h +++ b/include/WindowAccessor.h @@ -12,13 +12,14 @@ namespace Scintilla { /** */ + class WindowAccessor : public Accessor { // Private so WindowAccessor objects can not be copied WindowAccessor(const WindowAccessor &source) : Accessor(), props(source.props) {} WindowAccessor &operator=(const WindowAccessor &) { return *this; } protected: WindowID id; - PropSet &props; + PropertyGet &props; int lenDoc; char styleBuf[bufferSize]; @@ -30,7 +31,7 @@ protected: bool InternalIsLeadByte(char ch); void Fill(int position); public: - WindowAccessor(WindowID id_, PropSet &props_) : + WindowAccessor(WindowID id_, PropertyGet &props_) : Accessor(), id(id_), props(props_), lenDoc(-1), validLen(0), chFlags(0), chWhile(0) { } diff --git a/src/AutoComplete.cxx b/src/AutoComplete.cxx index af6154ea1..86c64df56 100644 --- a/src/AutoComplete.cxx +++ b/src/AutoComplete.cxx @@ -11,7 +11,7 @@ #include "Platform.h" -#include "PropSet.h" +#include "CharClassify.h" #include "AutoComplete.h" #ifdef SCI_NAMESPACE diff --git a/src/CharClassify.cxx b/src/CharClassify.cxx index acab4b229..42a0ff10e 100644 --- a/src/CharClassify.cxx +++ b/src/CharClassify.cxx @@ -41,3 +41,37 @@ void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) { } } } + +int CompareCaseInsensitive(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + } + // Either *a or *b is nul + return *a - *b; +} + +int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { + while (*a && *b && len) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + len--; + } + if (len == 0) + return 0; + else + // Either *a or *b is nul + return *a - *b; +} diff --git a/src/CharClassify.h b/src/CharClassify.h index 881d3a114..d746fe02d 100644 --- a/src/CharClassify.h +++ b/src/CharClassify.h @@ -2,7 +2,7 @@ /** @file CharClassify.h ** Character classifications used by Document and RESearch. **/ -// Copyright 2006 by Neil Hodgson <neilh@scintilla.org> +// Copyright 2006-2009 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARCLASSIFY_H @@ -22,4 +22,16 @@ private: enum { maxChar=256 }; unsigned char charClass[maxChar]; // not type cc to save space }; + +// These functions are implemented because each platform calls them something different. +int CompareCaseInsensitive(const char *a, const char *b); +int CompareNCaseInsensitive(const char *a, const char *b, size_t len); + +inline char MakeUpperCase(char ch) { + if (ch < 'a' || ch > 'z') + return ch; + else + return static_cast<char>(ch - 'a' + 'A'); +} + #endif diff --git a/src/Document.cxx b/src/Document.cxx index fdf8261d9..ab29c798a 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -1067,16 +1067,6 @@ bool Document::IsWordAt(int start, int end) { return IsWordStartAt(start) && IsWordEndAt(end); } -// The comparison and case changing functions here assume ASCII -// or extended ASCII such as the normal Windows code page. - -static inline char MakeUpperCase(char ch) { - if (ch < 'a' || ch > 'z') - return ch; - else - return static_cast<char>(ch - 'a' + 'A'); -} - static inline char MakeLowerCase(char ch) { if (ch < 'A' || ch > 'Z') return ch; diff --git a/src/DocumentAccessor.h b/src/DocumentAccessor.h index a3a939d0d..92440428e 100644 --- a/src/DocumentAccessor.h +++ b/src/DocumentAccessor.h @@ -14,6 +14,7 @@ class Document; /** */ + class DocumentAccessor : public Accessor { // Private so DocumentAccessor objects can not be copied DocumentAccessor(const DocumentAccessor &source) : Accessor(), props(source.props) {} @@ -21,7 +22,7 @@ class DocumentAccessor : public Accessor { protected: Document *pdoc; - PropSet &props; + PropertyGet &props; WindowID id; int lenDoc; @@ -37,7 +38,7 @@ protected: void Fill(int position); public: - DocumentAccessor(Document *pdoc_, PropSet &props_, WindowID id_=0) : + DocumentAccessor(Document *pdoc_, PropertyGet &props_, WindowID id_=0) : Accessor(), pdoc(pdoc_), props(props_), id(id_), lenDoc(-1), validLen(0), chFlags(0), chWhile(0), startSeg(0), startPosStyling(0), diff --git a/src/KeyWords.cxx b/src/KeyWords.cxx index 2e1e82882..366cb47dc 100644 --- a/src/KeyWords.cxx +++ b/src/KeyWords.cxx @@ -23,6 +23,192 @@ using namespace Scintilla; #endif +/** + * Creates an array that points into each word in the string and puts \0 terminators + * after each word. + */ +static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { + int prev = '\n'; + int words = 0; + // For rapid determination of whether a character is a separator, build + // a look up table. + bool wordSeparator[256]; + for (int i=0;i<256; i++) { + wordSeparator[i] = false; + } + wordSeparator['\r'] = true; + wordSeparator['\n'] = true; + if (!onlyLineEnds) { + wordSeparator[' '] = true; + wordSeparator['\t'] = true; + } + for (int j = 0; wordlist[j]; j++) { + int curr = static_cast<unsigned char>(wordlist[j]); + if (!wordSeparator[curr] && wordSeparator[prev]) + words++; + prev = curr; + } + char **keywords = new char *[words + 1]; + if (keywords) { + words = 0; + prev = '\0'; + size_t slen = strlen(wordlist); + for (size_t k = 0; k < slen; k++) { + if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) { + if (!prev) { + keywords[words] = &wordlist[k]; + words++; + } + } else { + wordlist[k] = '\0'; + } + prev = wordlist[k]; + } + keywords[words] = &wordlist[slen]; + *len = words; + } else { + *len = 0; + } + return keywords; +} + +void WordList::Clear() { + if (words) { + delete []list; + delete []words; + } + words = 0; + list = 0; + len = 0; + sorted = false; +} + +void WordList::Set(const char *s) { + list = new char[strlen(s) + 1]; + strcpy(list, s); + sorted = false; + words = ArrayFromWordList(list, &len, onlyLineEnds); +} + +extern "C" int cmpString(const void *a1, const void *a2) { + // Can't work out the correct incantation to use modern casts here + return strcmp(*(char**)(a1), *(char**)(a2)); +} + +static void SortWordList(char **words, unsigned int len) { + qsort(reinterpret_cast<void*>(words), len, sizeof(*words), + cmpString); +} + +bool WordList::InList(const char *s) { + if (0 == words) + return false; + if (!sorted) { + sorted = true; + SortWordList(words, len); + for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) + starts[k] = -1; + for (int l = len - 1; l >= 0; l--) { + unsigned char indexChar = words[l][0]; + starts[indexChar] = l; + } + } + unsigned char firstChar = s[0]; + int j = starts[firstChar]; + if (j >= 0) { + while ((unsigned char)words[j][0] == firstChar) { + if (s[1] == words[j][1]) { + const char *a = words[j] + 1; + const char *b = s + 1; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a && !*b) + return true; + } + j++; + } + } + j = starts['^']; + if (j >= 0) { + while (words[j][0] == '^') { + const char *a = words[j] + 1; + const char *b = s; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a) + return true; + j++; + } + } + return false; +} + +/** similar to InList, but word s can be a substring of keyword. + * eg. the keyword define is defined as def~ine. This means the word must start + * with def to be a keyword, but also defi, defin and define are valid. + * The marker is ~ in this case. + */ +bool WordList::InListAbbreviated(const char *s, const char marker) { + if (0 == words) + return false; + if (!sorted) { + sorted = true; + SortWordList(words, len); + for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) + starts[k] = -1; + for (int l = len - 1; l >= 0; l--) { + unsigned char indexChar = words[l][0]; + starts[indexChar] = l; + } + } + unsigned char firstChar = s[0]; + int j = starts[firstChar]; + if (j >= 0) { + while (words[j][0] == firstChar) { + bool isSubword = false; + int start = 1; + if (words[j][1] == marker) { + isSubword = true; + start++; + } + if (s[1] == words[j][start]) { + const char *a = words[j] + start; + const char *b = s + 1; + while (*a && *a == *b) { + a++; + if (*a == marker) { + isSubword = true; + a++; + } + b++; + } + if ((!*a || isSubword) && !*b) + return true; + } + j++; + } + } + j = starts['^']; + if (j >= 0) { + while (words[j][0] == '^') { + const char *a = words[j] + 1; + const char *b = s; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a) + return true; + j++; + } + } + return false; +} + const LexerModule *LexerModule::base = 0; int LexerModule::nextLanguage = SCLEX_AUTOMATIC+1; diff --git a/src/LexCaml.cxx b/src/LexCaml.cxx index 6570dcc07..0d1162259 100644 --- a/src/LexCaml.cxx +++ b/src/LexCaml.cxx @@ -27,6 +27,7 @@ #include "Platform.h" #include "PropSet.h" +#include "PropSetSimple.h" #include "Accessor.h" #include "StyleContext.h" #include "KeyWords.h" @@ -143,7 +144,7 @@ static void InternalLexOrFold(int foldOrLex, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { // create and initialize a WindowAccessor (including contained PropSet) - PropSet ps; + PropSetSimple ps; ps.SetMultiple(props); WindowAccessor wa(window, ps); // create and initialize WordList(s) diff --git a/src/LexCmake.cxx b/src/LexCmake.cxx index f63eb399f..1f51f474e 100644 --- a/src/LexCmake.cxx +++ b/src/LexCmake.cxx @@ -13,6 +13,7 @@ #include "Platform.h" +#include "CharClassify.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" diff --git a/src/LexHaskell.cxx b/src/LexHaskell.cxx index 3213bd520..b528f3f0e 100644 --- a/src/LexHaskell.cxx +++ b/src/LexHaskell.cxx @@ -25,6 +25,7 @@ #include "Platform.h" #include "PropSet.h" +#include "PropSetSimple.h" #include "Accessor.h" #include "StyleContext.h" #include "KeyWords.h" @@ -225,7 +226,7 @@ static const char* LexerName = "haskell"; void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { - PropSet ps; + PropSetSimple ps; ps.SetMultiple(props); WindowAccessor wa(window, ps); diff --git a/src/LexInno.cxx b/src/LexInno.cxx index 6da8548ff..6d1102c65 100644 --- a/src/LexInno.cxx +++ b/src/LexInno.cxx @@ -13,6 +13,7 @@ #include "Platform.h" +#include "CharClassify.h" #include "PropSet.h" #include "Accessor.h" #include "StyleContext.h" diff --git a/src/LexNsis.cxx b/src/LexNsis.cxx index ab6304c42..b16cc9baf 100644 --- a/src/LexNsis.cxx +++ b/src/LexNsis.cxx @@ -13,6 +13,7 @@ #include "Platform.h" +#include "CharClassify.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" diff --git a/src/LexOthers.cxx b/src/LexOthers.cxx index 1869014f8..75458f6d5 100644 --- a/src/LexOthers.cxx +++ b/src/LexOthers.cxx @@ -14,6 +14,7 @@ #include "Platform.h" +#include "CharClassify.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" diff --git a/src/PropSet.cxx b/src/PropSet.cxx index a1c366c3b..294d08e11 100644 --- a/src/PropSet.cxx +++ b/src/PropSet.cxx @@ -11,370 +11,53 @@ #include <string.h> #include <stdio.h> +#ifdef _MSC_VER +// Visual C++ doesn't like unreachable code or long decorated names in its own headers. +#pragma warning(disable: 4018 4100 4245 4511 4512 4663 4702 4786) +#endif + +#include <string> +#include <map> + #include "Platform.h" #include "PropSet.h" +#include "PropSetSimple.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif -// The comparison and case changing functions here assume ASCII -// or extended ASCII such as the normal Windows code page. - -static inline char MakeUpperCase(char ch) { - if (ch < 'a' || ch > 'z') - return ch; - else - return static_cast<char>(ch - 'a' + 'A'); -} - -static inline bool IsLetter(char ch) { - return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')); -} - -inline bool IsASpace(unsigned int ch) { - return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); -} - -int CompareCaseInsensitive(const char *a, const char *b) { - while (*a && *b) { - if (*a != *b) { - char upperA = MakeUpperCase(*a); - char upperB = MakeUpperCase(*b); - if (upperA != upperB) - return upperA - upperB; - } - a++; - b++; - } - // Either *a or *b is nul - return *a - *b; -} - -int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { - while (*a && *b && len) { - if (*a != *b) { - char upperA = MakeUpperCase(*a); - char upperB = MakeUpperCase(*b); - if (upperA != upperB) - return upperA - upperB; - } - a++; - b++; - len--; - } - if (len == 0) - return 0; - else - // Either *a or *b is nul - return *a - *b; -} - -bool EqualCaseInsensitive(const char *a, const char *b) { - return 0 == CompareCaseInsensitive(a, b); -} - -// Since the CaseInsensitive functions declared in SString -// are implemented here, I will for now put the non-inline -// implementations of the SString members here as well, so -// that I can quickly see what effect this has. - -SString::SString(int i) : sizeGrowth(sizeGrowthDefault) { - char number[32]; - sprintf(number, "%0d", i); - s = StringAllocate(number); - sSize = sLen = (s) ? strlen(s) : 0; -} - -SString::SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) { - char number[32]; - sprintf(number, "%.*f", precision, d); - s = StringAllocate(number); - sSize = sLen = (s) ? strlen(s) : 0; -} - -bool SString::grow(lenpos_t lenNew) { - while (sizeGrowth * 6 < lenNew) { - sizeGrowth *= 2; - } - char *sNew = new char[lenNew + sizeGrowth + 1]; - if (sNew) { - if (s) { - memcpy(sNew, s, sLen); - delete []s; - } - s = sNew; - s[sLen] = '\0'; - sSize = lenNew + sizeGrowth; - } - return sNew != 0; -} - -SString &SString::assign(const char *sOther, lenpos_t sSize_) { - if (!sOther) { - sSize_ = 0; - } else if (sSize_ == measure_length) { - sSize_ = strlen(sOther); - } - if (sSize > 0 && sSize_ <= sSize) { // Does not allocate new buffer if the current is big enough - if (s && sSize_) { - memcpy(s, sOther, sSize_); - } - s[sSize_] = '\0'; - sLen = sSize_; - } else { - delete []s; - s = StringAllocate(sOther, sSize_); - if (s) { - sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow - sLen = sSize_; - } else { - sSize = sLen = 0; - } - } - return *this; -} - -bool SString::operator==(const SString &sOther) const { - if ((s == 0) && (sOther.s == 0)) - return true; - if ((s == 0) || (sOther.s == 0)) - return false; - return strcmp(s, sOther.s) == 0; -} - -bool SString::operator==(const char *sOther) const { - if ((s == 0) && (sOther == 0)) - return true; - if ((s == 0) || (sOther == 0)) - return false; - return strcmp(s, sOther) == 0; -} - -SString SString::substr(lenpos_t subPos, lenpos_t subLen) const { - if (subPos >= sLen) { - return SString(); // return a null string if start index is out of bounds - } - if ((subLen == measure_length) || (subPos + subLen > sLen)) { - subLen = sLen - subPos; // can't substr past end of source string - } - return SString(s, subPos, subPos + subLen); -} +typedef std::map<std::string, std::string> mapss; -SString &SString::lowercase(lenpos_t subPos, lenpos_t subLen) { - if ((subLen == measure_length) || (subPos + subLen > sLen)) { - subLen = sLen - subPos; // don't apply past end of string - } - for (lenpos_t i = subPos; i < subPos + subLen; i++) { - if (s[i] < 'A' || s[i] > 'Z') - continue; - else - s[i] = static_cast<char>(s[i] - 'A' + 'a'); - } - return *this; +PropSetSimple::PropSetSimple() { + mapss *props = new mapss; + impl = static_cast<void *>(props); } -SString &SString::uppercase(lenpos_t subPos, lenpos_t subLen) { - if ((subLen == measure_length) || (subPos + subLen > sLen)) { - subLen = sLen - subPos; // don't apply past end of string - } - for (lenpos_t i = subPos; i < subPos + subLen; i++) { - if (s[i] < 'a' || s[i] > 'z') - continue; - else - s[i] = static_cast<char>(s[i] - 'a' + 'A'); - } - return *this; -} - -SString &SString::append(const char *sOther, lenpos_t sLenOther, char sep) { - if (!sOther) { - return *this; - } - if (sLenOther == measure_length) { - sLenOther = strlen(sOther); - } - int lenSep = 0; - if (sLen && sep) { // Only add a separator if not empty - lenSep = 1; - } - lenpos_t lenNew = sLen + sLenOther + lenSep; - // Conservative about growing the buffer: don't do it, unless really needed - if ((lenNew < sSize) || (grow(lenNew))) { - if (lenSep) { - s[sLen] = sep; - sLen++; - } - memcpy(&s[sLen], sOther, sLenOther); - sLen += sLenOther; - s[sLen] = '\0'; - } - return *this; -} - -SString &SString::insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther) { - if (!sOther || pos > sLen) { - return *this; - } - if (sLenOther == measure_length) { - sLenOther = strlen(sOther); - } - lenpos_t lenNew = sLen + sLenOther; - // Conservative about growing the buffer: don't do it, unless really needed - if ((lenNew < sSize) || grow(lenNew)) { - lenpos_t moveChars = sLen - pos + 1; - for (lenpos_t i = moveChars; i > 0; i--) { - s[pos + sLenOther + i - 1] = s[pos + i - 1]; - } - memcpy(s + pos, sOther, sLenOther); - sLen = lenNew; - } - return *this; +PropSetSimple::~PropSetSimple() { + mapss *props = static_cast<mapss *>(impl); + delete props; + impl = 0; } -/** - * Remove @a len characters from the @a pos position, included. - * Characters at pos + len and beyond replace characters at pos. - * If @a len is 0, or greater than the length of the string - * starting at @a pos, the string is just truncated at @a pos. - */ -void SString::remove(lenpos_t pos, lenpos_t len) { - if (pos >= sLen) { - return; - } - if (len < 1 || pos + len >= sLen) { - s[pos] = '\0'; - sLen = pos; - } else { - for (lenpos_t i = pos; i < sLen - len + 1; i++) { - s[i] = s[i+len]; - } - sLen -= len; - } -} - -bool SString::startswith(const char *prefix) { - lenpos_t lenPrefix = strlen(prefix); - if (lenPrefix > sLen) { - return false; - } - return strncmp(s, prefix, lenPrefix) == 0; -} - -bool SString::endswith(const char *suffix) { - lenpos_t lenSuffix = strlen(suffix); - if (lenSuffix > sLen) { - return false; - } - return strncmp(s + sLen - lenSuffix, suffix, lenSuffix) == 0; -} - -int SString::search(const char *sFind, lenpos_t start) const { - if (start < sLen) { - const char *sFound = strstr(s + start, sFind); - if (sFound) { - return sFound - s; - } - } - return -1; -} - -int SString::substitute(char chFind, char chReplace) { - int c = 0; - char *t = s; - while (t) { - t = strchr(t, chFind); - if (t) { - *t = chReplace; - t++; - c++; - } - } - return c; -} - -int SString::substitute(const char *sFind, const char *sReplace) { - int c = 0; - lenpos_t lenFind = strlen(sFind); - lenpos_t lenReplace = strlen(sReplace); - int posFound = search(sFind); - while (posFound >= 0) { - remove(posFound, lenFind); - insert(posFound, sReplace, lenReplace); - posFound = search(sFind, posFound + lenReplace); - c++; - } - return c; -} - -char *SContainer::StringAllocate(lenpos_t len) { - if (len != measure_length) { - return new char[len + 1]; - } else { - return 0; - } -} - -char *SContainer::StringAllocate(const char *s, lenpos_t len) { - if (s == 0) { - return 0; - } - if (len == measure_length) { - len = strlen(s); - } - char *sNew = new char[len + 1]; - if (sNew) { - memcpy(sNew, s, len); - sNew[len] = '\0'; - } - return sNew; -} - -// End SString functions - -PropSet::PropSet() { - superPS = 0; - for (int root = 0; root < hashRoots; root++) - props[root] = 0; -} - -PropSet::~PropSet() { - superPS = 0; - Clear(); -} - -void PropSet::Set(const char *key, const char *val, int lenKey, int lenVal) { +void PropSetSimple::Set(const char *key, const char *val, int lenKey, int lenVal) { + mapss *props = static_cast<mapss *>(impl); if (!*key) // Empty keys are not supported return; if (lenKey == -1) lenKey = static_cast<int>(strlen(key)); if (lenVal == -1) lenVal = static_cast<int>(strlen(val)); - unsigned int hash = HashString(key, lenKey); - for (Property *p = props[hash % hashRoots]; p; p = p->next) { - if ((hash == p->hash) && - ((strlen(p->key) == static_cast<unsigned int>(lenKey)) && - (0 == strncmp(p->key, key, lenKey)))) { - // Replace current value - delete [](p->val); - p->val = StringDup(val, lenVal); - return; - } - } - // Not found - Property *pNew = new Property; - if (pNew) { - pNew->hash = hash; - pNew->key = StringDup(key, lenKey); - pNew->val = StringDup(val, lenVal); - pNew->next = props[hash % hashRoots]; - props[hash % hashRoots] = pNew; - } + (*props)[std::string(key, lenKey)] = std::string(val, lenVal); } -void PropSet::Set(const char *keyVal) { - while (IsASpace(*keyVal)) +static bool IsASpaceCharacter(unsigned int ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +void PropSetSimple::Set(const char *keyVal) { + while (IsASpaceCharacter(*keyVal)) keyVal++; const char *endVal = keyVal; while (*endVal && (*endVal != '\n')) @@ -387,34 +70,7 @@ void PropSet::Set(const char *keyVal) { } } -void PropSet::Unset(const char *key, int lenKey) { - if (!*key) // Empty keys are not supported - return; - if (lenKey == -1) - lenKey = static_cast<int>(strlen(key)); - unsigned int hash = HashString(key, lenKey); - Property *pPrev = NULL; - for (Property *p = props[hash % hashRoots]; p; p = p->next) { - if ((hash == p->hash) && - ((strlen(p->key) == static_cast<unsigned int>(lenKey)) && - (0 == strncmp(p->key, key, lenKey)))) { - if (pPrev) - pPrev->next = p->next; - else - props[hash % hashRoots] = p->next; - if (p == enumnext) - enumnext = p->next; // Not that anyone should mix enum and Set / Unset. - delete [](p->key); - delete [](p->val); - delete p; - return; - } else { - pPrev = p; - } - } -} - -void PropSet::SetMultiple(const char *s) { +void PropSetSimple::SetMultiple(const char *s) { const char *eol = strchr(s, '\n'); while (eol) { Set(s); @@ -424,16 +80,11 @@ void PropSet::SetMultiple(const char *s) { Set(s); } -SString PropSet::Get(const char *key) const { - unsigned int hash = HashString(key, strlen(key)); - for (Property *p = props[hash % hashRoots]; p; p = p->next) { - if ((hash == p->hash) && (0 == strcmp(p->key, key))) { - return p->val; - } - } - if (superPS) { - // Failed here, so try in base property set - return superPS->Get(key); +const char *PropSetSimple::Get(const char *key) const { + mapss *props = static_cast<mapss *>(impl); + mapss::const_iterator keyPos = props->find(std::string(key)); + if (keyPos != props->end()) { + return keyPos->second.c_str(); } else { return ""; } @@ -456,300 +107,70 @@ struct VarChain { const VarChain *link; }; -static int ExpandAllInPlace(const PropSet &props, SString &withVars, int maxExpands, const VarChain &blankVars = VarChain()) { - int varStart = withVars.search("$("); - while ((varStart >= 0) && (maxExpands > 0)) { - int varEnd = withVars.search(")", varStart+2); - if (varEnd < 0) { +static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, int maxExpands, const VarChain &blankVars) { + size_t varStart = withVars.find("$("); + while ((varStart != std::string::npos) && (maxExpands > 0)) { + size_t varEnd = withVars.find(")", varStart+2); + if (varEnd == std::string::npos) { break; } // For consistency, when we see '$(ab$(cde))', expand the inner variable first, // regardless whether there is actually a degenerate variable named 'ab$(cde'. - int innerVarStart = withVars.search("$(", varStart+2); - while ((innerVarStart > varStart) && (innerVarStart < varEnd)) { + size_t innerVarStart = withVars.find("$(", varStart+2); + while ((innerVarStart != std::string::npos) && (innerVarStart > varStart) && (innerVarStart < varEnd)) { varStart = innerVarStart; - innerVarStart = withVars.search("$(", varStart+2); + innerVarStart = withVars.find("$(", varStart+2); } - SString var(withVars.c_str(), varStart + 2, varEnd); - SString val = props.Get(var.c_str()); + std::string var(withVars.c_str(), varStart + 2, varEnd - varStart - 2); + std::string val = props.Get(var.c_str()); if (blankVars.contains(var.c_str())) { - val.clear(); // treat blankVar as an empty string (e.g. to block self-reference) + val = ""; // treat blankVar as an empty string (e.g. to block self-reference) } if (--maxExpands >= 0) { maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars)); } - withVars.remove(varStart, varEnd-varStart+1); + withVars.erase(varStart, varEnd-varStart+1); withVars.insert(varStart, val.c_str(), val.length()); - varStart = withVars.search("$("); + varStart = withVars.find("$("); } return maxExpands; } -SString PropSet::GetExpanded(const char *key) const { - SString val = Get(key); +char *PropSetSimple::Expanded(const char *key) const { + std::string val = Get(key); ExpandAllInPlace(*this, val, 100, VarChain(key)); - return val; -} - -SString PropSet::Expand(const char *withVars, int maxExpands) const { - SString val = withVars; - ExpandAllInPlace(*this, val, maxExpands); - return val; -} - -int PropSet::GetInt(const char *key, int defaultValue) const { - SString val = GetExpanded(key); - if (val.length()) - return val.value(); - return defaultValue; -} - -bool isprefix(const char *target, const char *prefix) { - while (*target && *prefix) { - if (*target != *prefix) - return false; - target++; - prefix++; - } - if (*prefix) - return false; - else - return true; -} - -void PropSet::Clear() { - for (int root = 0; root < hashRoots; root++) { - Property *p = props[root]; - while (p) { - Property *pNext = p->next; - p->hash = 0; - delete []p->key; - p->key = 0; - delete []p->val; - p->val = 0; - delete p; - p = pNext; - } - props[root] = 0; - } -} - -char *PropSet::ToString() const { - size_t len=0; - for (int r = 0; r < hashRoots; r++) { - for (Property *p = props[r]; p; p = p->next) { - len += strlen(p->key) + 1; - len += strlen(p->val) + 1; - } - } - if (len == 0) - len = 1; // Return as empty string - char *ret = new char [len]; - if (ret) { - char *w = ret; - for (int root = 0; root < hashRoots; root++) { - for (Property *p = props[root]; p; p = p->next) { - strcpy(w, p->key); - w += strlen(p->key); - *w++ = '='; - strcpy(w, p->val); - w += strlen(p->val); - *w++ = '\n'; - } - } - ret[len-1] = '\0'; - } + char *ret = new char [val.size() + 1]; + strcpy(ret, val.c_str()); return ret; } -/** - * Creates an array that points into each word in the string and puts \0 terminators - * after each word. - */ -static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { - int prev = '\n'; - int words = 0; - // For rapid determination of whether a character is a separator, build - // a look up table. - bool wordSeparator[256]; - for (int i=0;i<256; i++) { - wordSeparator[i] = false; - } - wordSeparator['\r'] = true; - wordSeparator['\n'] = true; - if (!onlyLineEnds) { - wordSeparator[' '] = true; - wordSeparator['\t'] = true; - } - for (int j = 0; wordlist[j]; j++) { - int curr = static_cast<unsigned char>(wordlist[j]); - if (!wordSeparator[curr] && wordSeparator[prev]) - words++; - prev = curr; - } - char **keywords = new char *[words + 1]; - if (keywords) { - words = 0; - prev = '\0'; - size_t slen = strlen(wordlist); - for (size_t k = 0; k < slen; k++) { - if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) { - if (!prev) { - keywords[words] = &wordlist[k]; - words++; - } - } else { - wordlist[k] = '\0'; - } - prev = wordlist[k]; - } - keywords[words] = &wordlist[slen]; - *len = words; - } else { - *len = 0; - } - return keywords; -} - -void WordList::Clear() { - if (words) { - delete []list; - delete []words; - } - words = 0; - list = 0; - len = 0; - sorted = false; -} - -void WordList::Set(const char *s) { - list = StringDup(s); - sorted = false; - words = ArrayFromWordList(list, &len, onlyLineEnds); -} - -extern "C" int cmpString(const void *a1, const void *a2) { - // Can't work out the correct incantation to use modern casts here - return strcmp(*(char**)(a1), *(char**)(a2)); -} - -static void SortWordList(char **words, unsigned int len) { - qsort(reinterpret_cast<void*>(words), len, sizeof(*words), - cmpString); -} - -bool WordList::InList(const char *s) { - if (0 == words) - return false; - if (!sorted) { - sorted = true; - SortWordList(words, len); - for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) - starts[k] = -1; - for (int l = len - 1; l >= 0; l--) { - unsigned char indexChar = words[l][0]; - starts[indexChar] = l; - } - } - unsigned char firstChar = s[0]; - int j = starts[firstChar]; - if (j >= 0) { - while ((unsigned char)words[j][0] == firstChar) { - if (s[1] == words[j][1]) { - const char *a = words[j] + 1; - const char *b = s + 1; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a && !*b) - return true; - } - j++; - } - } - j = starts['^']; - if (j >= 0) { - while (words[j][0] == '^') { - const char *a = words[j] + 1; - const char *b = s; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a) - return true; - j++; - } +char *PropSetSimple::ToString() const { + mapss *props = static_cast<mapss *>(impl); + std::string sval; + for (mapss::const_iterator it=props->begin(); it != props->end(); it++) { + sval += it->first; + sval += "="; + sval += it->second; + sval += "\n"; } - return false; + char *ret = new char [sval.size() + 1]; + strcpy(ret, sval.c_str()); + return ret; } -/** similar to InList, but word s can be a substring of keyword. - * eg. the keyword define is defined as def~ine. This means the word must start - * with def to be a keyword, but also defi, defin and define are valid. - * The marker is ~ in this case. - */ -bool WordList::InListAbbreviated(const char *s, const char marker) { - if (0 == words) - return false; - if (!sorted) { - sorted = true; - SortWordList(words, len); - for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) - starts[k] = -1; - for (int l = len - 1; l >= 0; l--) { - unsigned char indexChar = words[l][0]; - starts[indexChar] = l; - } +int PropSetSimple::GetInt(const char *key, int defaultValue) const { + char *val = Expanded(key); + if (val) { + int retVal = atoi(val); + delete []val; + return retVal; } - unsigned char firstChar = s[0]; - int j = starts[firstChar]; - if (j >= 0) { - while (words[j][0] == firstChar) { - bool isSubword = false; - int start = 1; - if (words[j][1] == marker) { - isSubword = true; - start++; - } - if (s[1] == words[j][start]) { - const char *a = words[j] + start; - const char *b = s + 1; - while (*a && *a == *b) { - a++; - if (*a == marker) { - isSubword = true; - a++; - } - b++; - } - if ((!*a || isSubword) && !*b) - return true; - } - j++; - } - } - j = starts['^']; - if (j >= 0) { - while (words[j][0] == '^') { - const char *a = words[j] + 1; - const char *b = s; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a) - return true; - j++; - } - } - return false; + return defaultValue; } diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx index 5e2d9114b..3aba5fb7b 100644 --- a/src/ScintillaBase.cxx +++ b/src/ScintillaBase.cxx @@ -16,6 +16,7 @@ #include "Scintilla.h" #include "PropSet.h" +#include "PropSetSimple.h" #ifdef SCI_LEXER #include "SciLexer.h" #include "Accessor.h" @@ -706,24 +707,23 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara break; case SCI_GETPROPERTY: { - SString val = props.Get(reinterpret_cast<const char *>(wParam)); - const int n = val.length(); + const char *val = props.Get(reinterpret_cast<const char *>(wParam)); + const int n = strlen(val); if (lParam != 0) { char *ptr = reinterpret_cast<char *>(lParam); - memcpy(ptr, val.c_str(), n); - ptr[n] = '\0'; // terminate + strcpy(ptr, val); } return n; // Not including NUL } case SCI_GETPROPERTYEXPANDED: { - SString val = props.GetExpanded(reinterpret_cast<const char *>(wParam)); - const int n = val.length(); + char *val = props.Expanded(reinterpret_cast<const char *>(wParam)); + const int n = strlen(val); if (lParam != 0) { char *ptr = reinterpret_cast<char *>(lParam); - memcpy(ptr, val.c_str(), n); - ptr[n] = '\0'; // terminate + strcpy(ptr, val); } + delete []val; return n; // Not including NUL } diff --git a/src/ScintillaBase.h b/src/ScintillaBase.h index 0b414452a..15b514c2b 100644 --- a/src/ScintillaBase.h +++ b/src/ScintillaBase.h @@ -48,7 +48,7 @@ protected: #ifdef SCI_LEXER int lexLanguage; const LexerModule *lexCurrent; - PropSet props; + PropSetSimple props; enum {numWordLists=KEYWORDSET_MAX+1}; WordList *keyWordLists[numWordLists+1]; void SetLexer(uptr_t wParam); diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 34d013b7c..1b014e0a2 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -28,6 +28,7 @@ #ifdef SCI_LEXER #include "SciLexer.h" #include "PropSet.h" +#include "PropSetSimple.h" #include "Accessor.h" #include "KeyWords.h" #endif |