diff options
author | nyamatongwe <devnull@localhost> | 2001-05-01 11:12:42 +0000 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2001-05-01 11:12:42 +0000 |
commit | 2bf292a604d2b8e2bb07be283d8ab0067f24a43b (patch) | |
tree | 2d1d090c6804a9af2f81f04c4554c22e819a1487 /win32/ExternalLexer.cxx | |
parent | 581baaf98ebddddf0984b7b5bab90216069ac8b6 (diff) | |
download | scintilla-mirror-2bf292a604d2b8e2bb07be283d8ab0067f24a43b.tar.gz |
External lexer feature added by Simon allows lexers to be housed in DLLs with
a .lexer extension which are automatically loaded at startup.
Minor fix to IME support in ScintillaWin.cxx to deal with current mingw headers.
Diffstat (limited to 'win32/ExternalLexer.cxx')
-rw-r--r-- | win32/ExternalLexer.cxx | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/win32/ExternalLexer.cxx b/win32/ExternalLexer.cxx new file mode 100644 index 000000000..83aee0677 --- /dev/null +++ b/win32/ExternalLexer.cxx @@ -0,0 +1,283 @@ +// Scintilla source code edit control +/** @file ExternalLexer.cxx + ** Support external lexers in DLLs. + **/ +// Copyright 2001 Simon Steele <ss@pnotepad.org>, portions copyright Neil Hodgson. +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +#include "SciLexer.h" +#include "Platform.h" +#include "PropSet.h" +#include "Accessor.h" +#include "DocumentAccessor.h" +#include "KeyWords.h" +#include "ExternalLexer.h" + +// Initialise the static vars... +int LexerManager::UseCount = 0; +LexerLibrary *LexerManager::first = NULL; +LexerLibrary *LexerManager::last = NULL; + +//------------------------------------------ +// +// ExternalLexerModule +// +//------------------------------------------ + +char **WordListsToStrings(WordList *val[]) { + int dim = 0; + while (val[dim]) + dim++; + char **wls = new char * [dim + 1]; + for (int i = 0;i < dim;i++) { + SString words; + words = ""; + for (int n = 0; n < val[i]->len; n++) { + words += val[i]->words[n]; + if (n != val[i]->len - 1) + words += " "; + } + wls[i] = new char[words.length() + 1]; + strcpy(wls[i], words.c_str()); + } + wls[dim] = 0; + return wls; +} + +void DeleteWLStrings(char *strs[]) { + int dim = 0; + while (strs[dim]) { + delete strs[dim]; + dim++; + } + delete [] strs; +} + +void ExternalLexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) { + if (!fneLexer) + return ; + + char **kwds = WordListsToStrings(keywordlists); + char *ps = styler.GetProperties(); + + // The accessor passed in is always a DocumentAccessor so this cast and the subsequent + // access will work. Can not use the stricter dynamic_cast as that requires RTTI. + DocumentAccessor &da = static_cast<DocumentAccessor &>(styler); + WindowID wID = da.GetWindow(); + + fneLexer(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); + + delete ps; + DeleteWLStrings(kwds); +} + +void ExternalLexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) { + if (!fneFolder) + return ; + + char **kwds = WordListsToStrings(keywordlists); + char *ps = styler.GetProperties(); + + // The accessor passed in is always a DocumentAccessor so this cast and the subsequent + // access will work. Can not use the stricter dynamic_cast as that requires RTTI. + DocumentAccessor &da = static_cast<DocumentAccessor &>(styler); + WindowID wID = da.GetWindow(); + + fneFolder(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); + + delete ps; + DeleteWLStrings(kwds); +} + +void ExternalLexerModule::SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, int index) { + fneLexer = fLexer; + fneFolder = fFolder; + externalLanguage = index; +} + +//------------------------------------------ +// +// LexerLibrary +// +//------------------------------------------ + +LexerLibrary::LexerLibrary(LPCTSTR ModuleName) { + // Initialise some members... + first = NULL; + last = NULL; + + // Load the DLL + m_hModule = LoadLibrary(ModuleName); + if (m_hModule) { + m_sModuleName = ModuleName; + GetLexerCountFn GetLexerCount = (GetLexerCountFn)GetProcAddress(m_hModule, "GetLexerCount"); + + if (GetLexerCount) { + ExternalLexerModule *lex; + LexerMinder *lm; + + // Find functions in the DLL + GetLexerNameFn GetLexerName = (GetLexerNameFn)GetProcAddress(m_hModule, "GetLexerName"); + ExtLexerFunction Lexer = (ExtLexerFunction)GetProcAddress(m_hModule, "Lex"); + ExtFoldFunction Folder = (ExtFoldFunction)GetProcAddress(m_hModule, "Fold"); + + // Assign a buffer for the lexer name. + char lexname[100]; + strcpy(lexname, ""); + + int nl = GetLexerCount(); + + for (int i = 0; i < nl; i++) { + GetLexerName(i, lexname, 100); + lex = new ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL); + + // Create a LexerMinder so we don't leak the ExternalLexerModule... + lm = new LexerMinder; + lm->self = lex; + lm->next = NULL; + if (first != NULL) { + last->next = lm; + last = lm; + } else { + first = lm; + last = lm; + } + + // The external lexer needs to know how to call into its DLL to + // do its lexing and folding, we tell it here. Folder may be null. + lex->SetExternal(Lexer, Folder, i); + + } + } + } + next = NULL; +} + +LexerLibrary::~LexerLibrary() { + Release(); +} + +void LexerLibrary::Release() { + //TODO maintain a list of lexers created, and delete them! + LexerMinder *lm; + LexerMinder *next; + lm = first; + while (NULL != lm) { + next = lm->next; + delete lm->self; + delete lm; + lm = next; + } + + first = NULL; + last = NULL; + + // Release the DLL + if (NULL != m_hModule) { + FreeLibrary(m_hModule); + } +} + +//------------------------------------------ +// +// LexerManager +// +//------------------------------------------ + +int FindLastSlash(char *inp) { + int i; + int ret = -1; + for (i = strlen(inp) - 1; i >= 0; i--) { + if (inp[i] == '\\' || inp[i] == '/') { + // if you don't like break: + /* + if (ret == -1) + */ + ret = i; + break; + } + } + return ret; +} + +LexerManager::LexerManager() { + + UseCount++; + if (1 == UseCount) { + EnumerateLexers(); + } +} + +void LexerManager::EnumerateLexers() { + HANDLE hFind; + WIN32_FIND_DATA FindFileData; + + char path[MAX_PATH + 1]; + + GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH); + + int i = FindLastSlash(path); + + if (i == -1) + i = strlen(path); + + SString sPath(path, 0, i); + + // Ensure a trailing slash... + if ( sPath[sPath.size() - 1] != '/' && sPath[sPath.size() - 1] != '\\' ) { + sPath += '\\'; + } + + SString sPattern(sPath); + + sPattern.append("*.lexer"); + + hFind = FindFirstFile(sPattern.c_str(), &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) { + //Found the first file... + BOOL found = TRUE; + LexerLibrary *lib = NULL; + SString to_open; + + while (found) { + to_open.assign(sPath); + to_open += FindFileData.cFileName; + lib = new LexerLibrary(to_open.c_str()); + if (NULL != first) { + last->next = lib; + last = lib; + } else { + first = lib; + last = lib; + } + found = FindNextFile(hFind, &FindFileData); + } + + FindClose(hFind); + + } +} + +LexerManager::~LexerManager() { + // If this is the last LexerManager to be freed then + // we delete all of our LexerLibrarys. + UseCount--; + if (0 == UseCount) { + if (NULL != first) { + LexerLibrary *cur = first; + LexerLibrary *next = first->next; + while (first) { + delete cur; + cur = next; + } + first = NULL; + last = NULL; + } + } +} |