You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
6.1 KiB
259 lines
6.1 KiB
// 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 <string.h> |
|
#include <ctype.h> |
|
|
|
#include "Platform.h" |
|
|
|
#include "Scintilla.h" |
|
|
|
#include "SciLexer.h" |
|
#include "PropSet.h" |
|
#include "Accessor.h" |
|
#include "DocumentAccessor.h" |
|
#include "KeyWords.h" |
|
#include "ExternalLexer.h" |
|
|
|
LexerManager *LexerManager::theInstance = 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) const { |
|
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) const { |
|
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(const char* ModuleName) { |
|
// Initialise some members... |
|
first = NULL; |
|
last = NULL; |
|
|
|
// Load the DLL |
|
lib = DynamicLibrary::Load(ModuleName); |
|
if (lib->IsValid()) { |
|
m_sModuleName = ModuleName; |
|
//Cannot use reinterpret_cast because: ANSI C++ forbids casting between pointers to functions and objects |
|
GetLexerCountFn GetLexerCount = (GetLexerCountFn)(sptr_t)lib->FindFunction("GetLexerCount"); |
|
|
|
if (GetLexerCount) { |
|
ExternalLexerModule *lex; |
|
LexerMinder *lm; |
|
|
|
// Find functions in the DLL |
|
GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName"); |
|
ExtLexerFunction Lexer = (ExtLexerFunction)(sptr_t)lib->FindFunction("Lex"); |
|
ExtFoldFunction Folder = (ExtFoldFunction)(sptr_t)lib->FindFunction("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(); |
|
delete lib; |
|
} |
|
|
|
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; |
|
} |
|
|
|
//------------------------------------------ |
|
// |
|
// LexerManager |
|
// |
|
//------------------------------------------ |
|
|
|
/// Return the single LexerManager instance... |
|
LexerManager *LexerManager::GetInstance() { |
|
if(!theInstance) |
|
theInstance = new LexerManager; |
|
return theInstance; |
|
} |
|
|
|
/// Delete any LexerManager instance... |
|
void LexerManager::DeleteInstance() |
|
{ |
|
if(theInstance) { |
|
delete theInstance; |
|
theInstance = NULL; |
|
} |
|
} |
|
|
|
/// protected constructor - this is a singleton... |
|
LexerManager::LexerManager() { |
|
first = NULL; |
|
last = NULL; |
|
} |
|
|
|
LexerManager::~LexerManager() { |
|
Clear(); |
|
} |
|
|
|
void LexerManager::Load(const char* path) |
|
{ |
|
LoadLexerLibrary(path); |
|
} |
|
|
|
void LexerManager::LoadLexerLibrary(const char* module) |
|
{ |
|
LexerLibrary *lib = new LexerLibrary(module); |
|
if (NULL != first) { |
|
last->next = lib; |
|
last = lib; |
|
} else { |
|
first = lib; |
|
last = lib; |
|
} |
|
} |
|
|
|
void LexerManager::Clear() |
|
{ |
|
if (NULL != first) { |
|
LexerLibrary *cur = first; |
|
LexerLibrary *next; |
|
while (cur) { |
|
next = cur->next; |
|
delete cur; |
|
cur = next; |
|
} |
|
first = NULL; |
|
last = NULL; |
|
} |
|
} |
|
|
|
//------------------------------------------ |
|
// |
|
// LexerManager |
|
// |
|
//------------------------------------------ |
|
|
|
LMMinder::~LMMinder() |
|
{ |
|
LexerManager::DeleteInstance(); |
|
} |
|
|
|
LMMinder minder;
|
|
|