aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ExternalLexer.cxx
blob: fdef2ad57dab3c4f2f7dc156101cb721d8a73fa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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 <cstdlib>
#include <cassert>
#include <cstring>

#include <stdexcept>
#include <string>
#include <vector>
#include <memory>

#include "Platform.h"

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "LexerModule.h"
#include "Catalogue.h"
#include "ExternalLexer.h"

using namespace Scintilla;

std::unique_ptr<LexerManager> LexerManager::theInstance;

//------------------------------------------
//
// ExternalLexerModule
//
//------------------------------------------

void ExternalLexerModule::SetExternal(GetLexerFactoryFunction fFactory, int index) {
	fneFactory = fFactory;
	fnFactory = fFactory(index);
}

//------------------------------------------
//
// LexerLibrary
//
//------------------------------------------

LexerLibrary::LexerLibrary(const char *moduleName_) {
	// Load the DLL
	lib.reset(DynamicLibrary::Load(moduleName_));
	if (lib->IsValid()) {
		moduleName = 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) {
			// Find functions in the DLL
			GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName");
			GetLexerFactoryFunction fnFactory = (GetLexerFactoryFunction)(sptr_t)lib->FindFunction("GetLexerFactory");

			const int nl = GetLexerCount();

			for (int i = 0; i < nl; i++) {
				// Assign a buffer for the lexer name.
				char lexname[100] = "";
				GetLexerName(i, lexname, sizeof(lexname));
				ExternalLexerModule *lex = new ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL);
				Catalogue::AddLexerModule(lex);

				// Remember ExternalLexerModule so we don't leak it
				modules.push_back(std::unique_ptr<ExternalLexerModule>(lex));

				// The external lexer needs to know how to call into its DLL to
				// do its lexing and folding, we tell it here.
				lex->SetExternal(fnFactory, i);
			}
		}
	}
}

LexerLibrary::~LexerLibrary() {
}

//------------------------------------------
//
// LexerManager
//
//------------------------------------------

/// Return the single LexerManager instance...
LexerManager *LexerManager::GetInstance() {
	if (!theInstance)
		theInstance.reset(new LexerManager);
	return theInstance.get();
}

/// Delete any LexerManager instance...
void LexerManager::DeleteInstance() {
	theInstance.reset();
}

/// protected constructor - this is a singleton...
LexerManager::LexerManager() {
}

LexerManager::~LexerManager() {
	Clear();
}

void LexerManager::Load(const char *path) {
	for (const std::unique_ptr<LexerLibrary> &ll : libraries) {
		if (ll->moduleName == path)
			return;
	}
	LexerLibrary *lib = new LexerLibrary(path);
	libraries.push_back(std::unique_ptr<LexerLibrary>(lib));
}

void LexerManager::Clear() {
	libraries.clear();
}

//------------------------------------------
//
// LMMinder	-- trigger to clean up at exit.
//
//------------------------------------------

LMMinder::~LMMinder() {
	LexerManager::DeleteInstance();
}

LMMinder minder;