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