1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file ExternalLexer.cxx
3*8af74909SZhong Yang ** Support external lexers in DLLs or shared libraries.
4*8af74909SZhong Yang **/
5*8af74909SZhong Yang // Copyright 2001 Simon Steele <[email protected]>, portions copyright Neil Hodgson.
6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
7*8af74909SZhong Yang
8*8af74909SZhong Yang #include <cstdlib>
9*8af74909SZhong Yang #include <cassert>
10*8af74909SZhong Yang #include <cstring>
11*8af74909SZhong Yang
12*8af74909SZhong Yang #include <stdexcept>
13*8af74909SZhong Yang #include <string>
14*8af74909SZhong Yang #include <string_view>
15*8af74909SZhong Yang #include <vector>
16*8af74909SZhong Yang #include <memory>
17*8af74909SZhong Yang
18*8af74909SZhong Yang #include "Platform.h"
19*8af74909SZhong Yang
20*8af74909SZhong Yang #include "ILexer.h"
21*8af74909SZhong Yang #include "Scintilla.h"
22*8af74909SZhong Yang #include "SciLexer.h"
23*8af74909SZhong Yang
24*8af74909SZhong Yang #include "LexerModule.h"
25*8af74909SZhong Yang #include "Catalogue.h"
26*8af74909SZhong Yang #include "ExternalLexer.h"
27*8af74909SZhong Yang
28*8af74909SZhong Yang using namespace Scintilla;
29*8af74909SZhong Yang
30*8af74909SZhong Yang #if PLAT_WIN
31*8af74909SZhong Yang #define EXT_LEXER_DECL __stdcall
32*8af74909SZhong Yang #else
33*8af74909SZhong Yang #define EXT_LEXER_DECL
34*8af74909SZhong Yang #endif
35*8af74909SZhong Yang
36*8af74909SZhong Yang namespace {
37*8af74909SZhong Yang
38*8af74909SZhong Yang int nextLanguage = SCLEX_AUTOMATIC + 1;
39*8af74909SZhong Yang
40*8af74909SZhong Yang typedef int (EXT_LEXER_DECL *GetLexerCountFn)();
41*8af74909SZhong Yang typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength);
42*8af74909SZhong Yang typedef LexerFactoryFunction(EXT_LEXER_DECL *GetLexerFactoryFunction)(unsigned int Index);
43*8af74909SZhong Yang
44*8af74909SZhong Yang /// Generic function to convert from a void* to a function pointer.
45*8af74909SZhong Yang /// This avoids undefined and conditionally defined behaviour.
46*8af74909SZhong Yang template<typename T>
FunctionPointer(void * function)47*8af74909SZhong Yang T FunctionPointer(void *function) noexcept {
48*8af74909SZhong Yang static_assert(sizeof(T) == sizeof(function));
49*8af74909SZhong Yang T fp;
50*8af74909SZhong Yang memcpy(&fp, &function, sizeof(T));
51*8af74909SZhong Yang return fp;
52*8af74909SZhong Yang }
53*8af74909SZhong Yang
54*8af74909SZhong Yang /// Sub-class of LexerModule to use an external lexer.
55*8af74909SZhong Yang class ExternalLexerModule : public LexerModule {
56*8af74909SZhong Yang protected:
57*8af74909SZhong Yang GetLexerFactoryFunction fneFactory;
58*8af74909SZhong Yang std::string name;
59*8af74909SZhong Yang public:
ExternalLexerModule(int language_,LexerFunction fnLexer_,const char * languageName_=nullptr,LexerFunction fnFolder_=nullptr)60*8af74909SZhong Yang ExternalLexerModule(int language_, LexerFunction fnLexer_,
61*8af74909SZhong Yang const char *languageName_=nullptr, LexerFunction fnFolder_=nullptr) :
62*8af74909SZhong Yang LexerModule(language_, fnLexer_, nullptr, fnFolder_),
63*8af74909SZhong Yang fneFactory(nullptr), name(languageName_){
64*8af74909SZhong Yang languageName = name.c_str();
65*8af74909SZhong Yang }
66*8af74909SZhong Yang void SetExternal(GetLexerFactoryFunction fFactory, int index) noexcept;
67*8af74909SZhong Yang };
68*8af74909SZhong Yang
69*8af74909SZhong Yang /// LexerLibrary exists for every External Lexer DLL, contains ExternalLexerModules.
70*8af74909SZhong Yang class LexerLibrary {
71*8af74909SZhong Yang std::unique_ptr<DynamicLibrary> lib;
72*8af74909SZhong Yang std::vector<std::unique_ptr<ExternalLexerModule>> modules;
73*8af74909SZhong Yang public:
74*8af74909SZhong Yang explicit LexerLibrary(const char *moduleName_);
75*8af74909SZhong Yang ~LexerLibrary();
76*8af74909SZhong Yang
77*8af74909SZhong Yang std::string moduleName;
78*8af74909SZhong Yang };
79*8af74909SZhong Yang
80*8af74909SZhong Yang /// LexerManager manages external lexers, contains LexerLibrarys.
81*8af74909SZhong Yang class LexerManager {
82*8af74909SZhong Yang public:
83*8af74909SZhong Yang ~LexerManager();
84*8af74909SZhong Yang
85*8af74909SZhong Yang static LexerManager *GetInstance();
86*8af74909SZhong Yang static void DeleteInstance() noexcept;
87*8af74909SZhong Yang
88*8af74909SZhong Yang void Load(const char *path);
89*8af74909SZhong Yang void Clear() noexcept;
90*8af74909SZhong Yang
91*8af74909SZhong Yang private:
92*8af74909SZhong Yang LexerManager();
93*8af74909SZhong Yang static std::unique_ptr<LexerManager> theInstance;
94*8af74909SZhong Yang std::vector<std::unique_ptr<LexerLibrary>> libraries;
95*8af74909SZhong Yang };
96*8af74909SZhong Yang
97*8af74909SZhong Yang class LMMinder {
98*8af74909SZhong Yang public:
99*8af74909SZhong Yang ~LMMinder();
100*8af74909SZhong Yang };
101*8af74909SZhong Yang
102*8af74909SZhong Yang std::unique_ptr<LexerManager> LexerManager::theInstance;
103*8af74909SZhong Yang
104*8af74909SZhong Yang //------------------------------------------
105*8af74909SZhong Yang //
106*8af74909SZhong Yang // ExternalLexerModule
107*8af74909SZhong Yang //
108*8af74909SZhong Yang //------------------------------------------
109*8af74909SZhong Yang
SetExternal(GetLexerFactoryFunction fFactory,int index)110*8af74909SZhong Yang void ExternalLexerModule::SetExternal(GetLexerFactoryFunction fFactory, int index) noexcept {
111*8af74909SZhong Yang fneFactory = fFactory;
112*8af74909SZhong Yang fnFactory = fFactory(index);
113*8af74909SZhong Yang }
114*8af74909SZhong Yang
115*8af74909SZhong Yang //------------------------------------------
116*8af74909SZhong Yang //
117*8af74909SZhong Yang // LexerLibrary
118*8af74909SZhong Yang //
119*8af74909SZhong Yang //------------------------------------------
120*8af74909SZhong Yang
LexerLibrary(const char * moduleName_)121*8af74909SZhong Yang LexerLibrary::LexerLibrary(const char *moduleName_) {
122*8af74909SZhong Yang // Load the DLL
123*8af74909SZhong Yang lib.reset(DynamicLibrary::Load(moduleName_));
124*8af74909SZhong Yang if (lib->IsValid()) {
125*8af74909SZhong Yang moduleName = moduleName_;
126*8af74909SZhong Yang GetLexerCountFn GetLexerCount = FunctionPointer<GetLexerCountFn>(lib->FindFunction("GetLexerCount"));
127*8af74909SZhong Yang
128*8af74909SZhong Yang if (GetLexerCount) {
129*8af74909SZhong Yang // Find functions in the DLL
130*8af74909SZhong Yang GetLexerNameFn GetLexerName = FunctionPointer<GetLexerNameFn>(lib->FindFunction("GetLexerName"));
131*8af74909SZhong Yang GetLexerFactoryFunction fnFactory = FunctionPointer<GetLexerFactoryFunction>(lib->FindFunction("GetLexerFactory"));
132*8af74909SZhong Yang
133*8af74909SZhong Yang if (!GetLexerName || !fnFactory) {
134*8af74909SZhong Yang return;
135*8af74909SZhong Yang }
136*8af74909SZhong Yang
137*8af74909SZhong Yang const int nl = GetLexerCount();
138*8af74909SZhong Yang
139*8af74909SZhong Yang for (int i = 0; i < nl; i++) {
140*8af74909SZhong Yang // Assign a buffer for the lexer name.
141*8af74909SZhong Yang char lexname[100] = "";
142*8af74909SZhong Yang GetLexerName(i, lexname, sizeof(lexname));
143*8af74909SZhong Yang ExternalLexerModule *lex = new ExternalLexerModule(nextLanguage, nullptr, lexname, nullptr);
144*8af74909SZhong Yang nextLanguage++;
145*8af74909SZhong Yang
146*8af74909SZhong Yang // This is storing a second reference to lex in the Catalogue as well as in modules.
147*8af74909SZhong Yang // TODO: Should use std::shared_ptr or similar to ensure allocation safety.
148*8af74909SZhong Yang Catalogue::AddLexerModule(lex);
149*8af74909SZhong Yang
150*8af74909SZhong Yang // Remember ExternalLexerModule so we don't leak it
151*8af74909SZhong Yang modules.push_back(std::unique_ptr<ExternalLexerModule>(lex));
152*8af74909SZhong Yang
153*8af74909SZhong Yang // The external lexer needs to know how to call into its DLL to
154*8af74909SZhong Yang // do its lexing and folding, we tell it here.
155*8af74909SZhong Yang lex->SetExternal(fnFactory, i);
156*8af74909SZhong Yang }
157*8af74909SZhong Yang }
158*8af74909SZhong Yang }
159*8af74909SZhong Yang }
160*8af74909SZhong Yang
~LexerLibrary()161*8af74909SZhong Yang LexerLibrary::~LexerLibrary() {
162*8af74909SZhong Yang }
163*8af74909SZhong Yang
164*8af74909SZhong Yang //------------------------------------------
165*8af74909SZhong Yang //
166*8af74909SZhong Yang // LexerManager
167*8af74909SZhong Yang //
168*8af74909SZhong Yang //------------------------------------------
169*8af74909SZhong Yang
170*8af74909SZhong Yang /// Return the single LexerManager instance...
GetInstance()171*8af74909SZhong Yang LexerManager *LexerManager::GetInstance() {
172*8af74909SZhong Yang if (!theInstance)
173*8af74909SZhong Yang theInstance.reset(new LexerManager);
174*8af74909SZhong Yang return theInstance.get();
175*8af74909SZhong Yang }
176*8af74909SZhong Yang
177*8af74909SZhong Yang /// Delete any LexerManager instance...
DeleteInstance()178*8af74909SZhong Yang void LexerManager::DeleteInstance() noexcept {
179*8af74909SZhong Yang theInstance.reset();
180*8af74909SZhong Yang }
181*8af74909SZhong Yang
182*8af74909SZhong Yang /// protected constructor - this is a singleton...
LexerManager()183*8af74909SZhong Yang LexerManager::LexerManager() {
184*8af74909SZhong Yang }
185*8af74909SZhong Yang
~LexerManager()186*8af74909SZhong Yang LexerManager::~LexerManager() {
187*8af74909SZhong Yang Clear();
188*8af74909SZhong Yang }
189*8af74909SZhong Yang
Load(const char * path)190*8af74909SZhong Yang void LexerManager::Load(const char *path) {
191*8af74909SZhong Yang for (const std::unique_ptr<LexerLibrary> &ll : libraries) {
192*8af74909SZhong Yang if (ll->moduleName == path)
193*8af74909SZhong Yang return;
194*8af74909SZhong Yang }
195*8af74909SZhong Yang libraries.push_back(std::make_unique<LexerLibrary>(path));
196*8af74909SZhong Yang }
197*8af74909SZhong Yang
Clear()198*8af74909SZhong Yang void LexerManager::Clear() noexcept {
199*8af74909SZhong Yang libraries.clear();
200*8af74909SZhong Yang }
201*8af74909SZhong Yang
202*8af74909SZhong Yang //------------------------------------------
203*8af74909SZhong Yang //
204*8af74909SZhong Yang // LMMinder -- trigger to clean up at exit.
205*8af74909SZhong Yang //
206*8af74909SZhong Yang //------------------------------------------
207*8af74909SZhong Yang
~LMMinder()208*8af74909SZhong Yang LMMinder::~LMMinder() {
209*8af74909SZhong Yang LexerManager::DeleteInstance();
210*8af74909SZhong Yang }
211*8af74909SZhong Yang
212*8af74909SZhong Yang LMMinder minder;
213*8af74909SZhong Yang
214*8af74909SZhong Yang }
215*8af74909SZhong Yang
216*8af74909SZhong Yang namespace Scintilla {
217*8af74909SZhong Yang
ExternalLexerLoad(const char * path)218*8af74909SZhong Yang void ExternalLexerLoad(const char *path) {
219*8af74909SZhong Yang LexerManager::GetInstance()->Load(path);
220*8af74909SZhong Yang }
221*8af74909SZhong Yang
222*8af74909SZhong Yang }
223