// Scintilla source code edit control /** @file KeyWords.cxx ** Colourise for particular languages. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" #ifdef SCI_NAMESPACE 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(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(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(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; LexerModule::LexerModule(int language_, LexerFunction fnLexer_, const char *languageName_, LexerFunction fnFolder_, const char *const wordListDescriptions_[], int styleBits_) : language(language_), fnLexer(fnLexer_), fnFolder(fnFolder_), wordListDescriptions(wordListDescriptions_), styleBits(styleBits_), languageName(languageName_) { next = base; base = this; if (language == SCLEX_AUTOMATIC) { language = nextLanguage; nextLanguage++; } } int LexerModule::GetNumWordLists() const { if (wordListDescriptions == NULL) { return -1; } else { int numWordLists = 0; while (wordListDescriptions[numWordLists]) { ++numWordLists; } return numWordLists; } } const char *LexerModule::GetWordListDescription(int index) const { static const char *emptyStr = ""; PLATFORM_ASSERT(index < GetNumWordLists()); if (index >= GetNumWordLists()) { return emptyStr; } else { return wordListDescriptions[index]; } } int LexerModule::GetStyleBitsNeeded() const { return styleBits; } const LexerModule *LexerModule::Find(int language) { const LexerModule *lm = base; while (lm) { if (lm->language == language) { return lm; } lm = lm->next; } return 0; } const LexerModule *LexerModule::Find(const char *languageName) { if (languageName) { const LexerModule *lm = base; while (lm) { if (lm->languageName && 0 == strcmp(lm->languageName, languageName)) { return lm; } lm = lm->next; } } return 0; } void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnLexer) fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler); } void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnFolder) { int lineCurrent = styler.GetLine(startPos); // Move back one line in case deletion wrecked current line fold state if (lineCurrent > 0) { lineCurrent--; int newStartPos = styler.LineStart(lineCurrent); lengthDoc += startPos - newStartPos; startPos = newStartPos; initStyle = 0; if (startPos > 0) { initStyle = styler.StyleAt(startPos - 1); } } fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler); } } // Alternative historical name for Scintilla_LinkLexers int wxForceScintillaLexers(void) { return Scintilla_LinkLexers(); } // To add or remove a lexer, add or remove its file and run LexGen.py. // Force a reference to all of the Scintilla lexers so that the linker will // not remove the code of the lexers. int Scintilla_LinkLexers() { static int forcer = 0; // Shorten the code that declares a lexer and ensures it is linked in by calling a method. #define LINK_LEXER(lexer) extern LexerModule lexer; forcer += lexer.GetLanguage(); //++Autogenerated -- run src/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) LINK_LEXER(lmAbaqus); LINK_LEXER(lmAda); LINK_LEXER(lmAns1); LINK_LEXER(lmAPDL); LINK_LEXER(lmAsm); LINK_LEXER(lmASY); LINK_LEXER(lmAU3); LINK_LEXER(lmAVE); LINK_LEXER(lmBaan); LINK_LEXER(lmBash); LINK_LEXER(lmBatch); LINK_LEXER(lmBlitzBasic); LINK_LEXER(lmBullant); LINK_LEXER(lmCaml); LINK_LEXER(lmClw); LINK_LEXER(lmClwNoCase); LINK_LEXER(lmCmake); LINK_LEXER(lmCOBOL); LINK_LEXER(lmConf); LINK_LEXER(lmCPP); LINK_LEXER(lmCPPNoCase); LINK_LEXER(lmCsound); LINK_LEXER(lmCss); LINK_LEXER(lmD); LINK_LEXER(lmDiff); LINK_LEXER(lmHTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="KeyWords.cxx" Content-Disposition: inline; filename="KeyWords.cxx" Content-Disposition: inline; filename="KeyWords.cxx" Content-Length: 9812 Content-Length: 9812 Content-Length: 9812 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Sat, 18 Oct 2025 04:06:23 UTC ETag: "17bda87662178a0c1a3b0ce031b563a6f0041e79" ETag: "17bda87662178a0c1a3b0ce031b563a6f0041e79" ETag: "17bda87662178a0c1a3b0ce031b563a6f0041e79" Expires: Tue, 16 Oct 2035 04:06:23 GMT Expires: Tue, 16 Oct 2035 04:06:23 GMT Expires: Tue, 16 Oct 2035 04:06:24 GMT Last-Modified: Sat, 18 Oct 2025 04:06:23 GMT Last-Modified: Sat, 18 Oct 2025 04:06:23 GMT Last-Modified: Sat, 18 Oct 2025 04:06:24 GMT Server: OpenBSD httpd Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff // Scintilla source code edit control /** @file KeyWords.cxx ** Colourise for particular languages. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #i