xref: /MusicPlayer2/scintilla/src/ExternalLexer.cxx (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
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