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 | 
