diff options
author | nyamatongwe <unknown> | 2009-07-21 09:05:43 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2009-07-21 09:05:43 +0000 |
commit | 7b7af48a7681ab335ba2c53ffa48ab053ddf4c86 (patch) | |
tree | 6039e12ca6c8f447ca34fbe3c3b0195d4c3a2372 /src | |
parent | f20e894bd45438901560b6838cea7d4639f1e5c6 (diff) | |
download | scintilla-mirror-7b7af48a7681ab335ba2c53ffa48ab053ddf4c86.tar.gz |
Using a much simpler property set implementation.
Accessor objects use the PropertyGet interface to access just the property
set methods they need.
Removed SString.
Diffstat (limited to 'src')
-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 |
15 files changed, 321 insertions, 671 deletions
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); |