1 // Scintilla source code edit control
2 /** @file LexInno.cxx
3  ** Lexer for Inno Setup scripts.
4  **/
5 // Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx.
6 // The License.txt file describes the conditions under which this software may be distributed.
7 
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 
14 #include "Platform.h"
15 
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "StyleContext.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22 
ColouriseInnoDoc(unsigned int startPos,int length,int,WordList * keywordLists[],Accessor & styler)23 static void ColouriseInnoDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) {
24 	int state = SCE_INNO_DEFAULT;
25 	char chPrev;
26 	char ch = 0;
27 	char chNext = styler[startPos];
28 	int lengthDoc = startPos + length;
29 	char *buffer = new char[length];
30 	int bufferCount = 0;
31 	bool isBOL, isEOL, isWS, isBOLWS = 0;
32 
33 	WordList &sectionKeywords = *keywordLists[0];
34 	WordList &standardKeywords = *keywordLists[1];
35 	WordList &parameterKeywords = *keywordLists[2];
36 	WordList &preprocessorKeywords = *keywordLists[3];
37 	WordList &pascalKeywords = *keywordLists[4];
38 	WordList &userKeywords = *keywordLists[5];
39 
40 	// Go through all provided text segment
41 	// using the hand-written state machine shown below
42 	styler.StartAt(startPos);
43 	styler.StartSegment(startPos);
44 	for (int i = startPos; i < lengthDoc; i++) {
45 		chPrev = ch;
46 		ch = chNext;
47 		chNext = styler.SafeGetCharAt(i + 1);
48 
49 		if (styler.IsLeadByte(ch)) {
50 			chNext = styler.SafeGetCharAt(i + 2);
51 			i++;
52 			continue;
53 		}
54 
55 		isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n');
56 		isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t'));
57 		isEOL = (ch == '\n' || ch == '\r');
58 		isWS = (ch == ' ' || ch == '\t');
59 
60 		switch(state) {
61 			case SCE_INNO_DEFAULT:
62 				if (ch == ';' && isBOLWS) {
63 					// Start of a comment
64 					state = SCE_INNO_COMMENT;
65 				} else if (ch == '[' && isBOLWS) {
66 					// Start of a section name
67 					bufferCount = 0;
68 					state = SCE_INNO_SECTION;
69 				} else if (ch == '#' && isBOLWS) {
70 					// Start of a preprocessor directive
71 					state = SCE_INNO_PREPROC;
72 				} else if (ch == '{' && chNext == '#') {
73 					// Start of a preprocessor inline directive
74 					state = SCE_INNO_PREPROC_INLINE;
75 				} else if ((ch == '{' && (chNext == ' ' || chNext == '\t'))
76 					   || (ch == '(' && chNext == '*')) {
77 					// Start of a Pascal comment
78 					state = SCE_INNO_COMMENT_PASCAL;
79 				} else if (ch == '"') {
80 					// Start of a double-quote string
81 					state = SCE_INNO_STRING_DOUBLE;
82 				} else if (ch == '\'') {
83 					// Start of a single-quote string
84 					state = SCE_INNO_STRING_SINGLE;
85 				} else if (isascii(ch) && (isalpha(ch) || (ch == '_'))) {
86 					// Start of an identifier
87 					bufferCount = 0;
88 					buffer[bufferCount++] = static_cast<char>(tolower(ch));
89 					state = SCE_INNO_IDENTIFIER;
90 				} else {
91 					// Style it the default style
92 					styler.ColourTo(i,SCE_INNO_DEFAULT);
93 				}
94 				break;
95 
96 			case SCE_INNO_COMMENT:
97 				if (isEOL) {
98 					state = SCE_INNO_DEFAULT;
99 					styler.ColourTo(i,SCE_INNO_COMMENT);
100 				}
101 				break;
102 
103 			case SCE_INNO_IDENTIFIER:
104 				if (isascii(ch) && (isalnum(ch) || (ch == '_'))) {
105 					buffer[bufferCount++] = static_cast<char>(tolower(ch));
106 				} else {
107 					state = SCE_INNO_DEFAULT;
108 					buffer[bufferCount] = '\0';
109 
110 					// Check if the buffer contains a keyword
111 					if (standardKeywords.InList(buffer)) {
112 						styler.ColourTo(i-1,SCE_INNO_KEYWORD);
113 					} else if (parameterKeywords.InList(buffer)) {
114 						styler.ColourTo(i-1,SCE_INNO_PARAMETER);
115 					} else if (pascalKeywords.InList(buffer)) {
116 						styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL);
117 					} else if (userKeywords.InList(buffer)) {
118 						styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER);
119 					} else {
120 						styler.ColourTo(i-1,SCE_INNO_DEFAULT);
121 					}
122 
123 					// Push back the faulty character
124 					chNext = styler[i--];
125 					ch = chPrev;
126 				}
127 				break;
128 
129 			case SCE_INNO_SECTION:
130 				if (ch == ']') {
131 					state = SCE_INNO_DEFAULT;
132 					buffer[bufferCount] = '\0';
133 
134 					// Check if the buffer contains a section name
135 					if (sectionKeywords.InList(buffer)) {
136 						styler.ColourTo(i,SCE_INNO_SECTION);
137 					} else {
138 						styler.ColourTo(i,SCE_INNO_DEFAULT);
139 					}
140 				} else if (isascii(ch) && (isalnum(ch) || (ch == '_'))) {
141 					buffer[bufferCount++] = static_cast<char>(tolower(ch));
142 				} else {
143 					state = SCE_INNO_DEFAULT;
144 					styler.ColourTo(i,SCE_INNO_DEFAULT);
145 				}
146 				break;
147 
148 			case SCE_INNO_PREPROC:
149 				if (isWS || isEOL) {
150 					if (isascii(chPrev) && isalpha(chPrev)) {
151 						state = SCE_INNO_DEFAULT;
152 						buffer[bufferCount] = '\0';
153 
154 						// Check if the buffer contains a preprocessor directive
155 						if (preprocessorKeywords.InList(buffer)) {
156 							styler.ColourTo(i-1,SCE_INNO_PREPROC);
157 						} else {
158 							styler.ColourTo(i-1,SCE_INNO_DEFAULT);
159 						}
160 
161 						// Push back the faulty character
162 						chNext = styler[i--];
163 						ch = chPrev;
164 					}
165 				} else if (isascii(ch) && isalpha(ch)) {
166 					if (chPrev == '#' || chPrev == ' ' || chPrev == '\t')
167 						bufferCount = 0;
168 					buffer[bufferCount++] = static_cast<char>(tolower(ch));
169 				}
170 				break;
171 
172 			case SCE_INNO_STRING_DOUBLE:
173 				if (ch == '"' || isEOL) {
174 					state = SCE_INNO_DEFAULT;
175 					styler.ColourTo(i,SCE_INNO_DEFAULT);
176 				}
177 				break;
178 
179 			case SCE_INNO_STRING_SINGLE:
180 				if (ch == '\'' || isEOL) {
181 					state = SCE_INNO_DEFAULT;
182 					styler.ColourTo(i,SCE_INNO_DEFAULT);
183 				}
184 				break;
185 
186 			case SCE_INNO_PREPROC_INLINE:
187 				if (ch == '}') {
188 					state = SCE_INNO_DEFAULT;
189 					styler.ColourTo(i,SCE_INNO_PREPROC_INLINE);
190 				} else if (isEOL) {
191 					state = SCE_INNO_DEFAULT;
192 					styler.ColourTo(i,SCE_INNO_DEFAULT);
193 				}
194 				break;
195 
196 			case SCE_INNO_COMMENT_PASCAL:
197 				if (ch == '}' || (ch == ')' && chPrev == '*')) {
198 					state = SCE_INNO_DEFAULT;
199 					styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
200 				} else if (isEOL) {
201 					state = SCE_INNO_DEFAULT;
202 					styler.ColourTo(i,SCE_INNO_DEFAULT);
203 				}
204 				break;
205 
206 		}
207 	}
208 	delete []buffer;
209 }
210 
211 static const char * const innoWordListDesc[] = {
212 	"Sections",
213 	"Keywords",
214 	"Parameters",
215 	"Preprocessor directives",
216 	"Pascal keywords",
217 	"User defined keywords",
218 	0
219 };
220 
FoldInnoDoc(unsigned int startPos,int length,int,WordList * [],Accessor & styler)221 static void FoldInnoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
222 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
223 
224 	unsigned int endPos = startPos + length;
225 	int visibleChars = 0;
226 	int lineCurrent = styler.GetLine(startPos);
227 
228 	char chNext = styler[startPos];
229 	int styleNext = styler.StyleAt(startPos);
230 	bool headerPoint = false;
231 	int lev;
232 
233 	for (unsigned int i = startPos; i < endPos; i++) {
234 		char ch = chNext;
235 		chNext = styler[i+1];
236 
237 		int style = styleNext;
238 		styleNext = styler.StyleAt(i + 1);
239 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
240 
241 		if (style == SCE_INNO_SECTION)
242 			headerPoint = true;
243 
244 		if (atEOL) {
245 			lev = SC_FOLDLEVELBASE;
246 
247 			if (lineCurrent > 0) {
248 				int levelPrevious = styler.LevelAt(lineCurrent - 1);
249 
250 				if (levelPrevious & SC_FOLDLEVELHEADERFLAG)
251 					lev = SC_FOLDLEVELBASE + 1;
252 				else
253 					lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;
254 			}
255 
256 			if (headerPoint)
257 				lev = SC_FOLDLEVELBASE;
258 
259 			if (visibleChars == 0 && foldCompact)
260 				lev |= SC_FOLDLEVELWHITEFLAG;
261 
262 			if (headerPoint)
263 				lev |= SC_FOLDLEVELHEADERFLAG;
264 
265 			if (lev != styler.LevelAt(lineCurrent))
266 				styler.SetLevel(lineCurrent, lev);
267 
268 			lineCurrent++;
269 			visibleChars = 0;
270 			headerPoint = false;
271 		}
272 		if (!isspacechar(ch))
273 			visibleChars++;
274 	}
275 
276 	if (lineCurrent > 0) {
277 		int levelPrevious = styler.LevelAt(lineCurrent - 1);
278 
279 		if (levelPrevious & SC_FOLDLEVELHEADERFLAG)
280 			lev = SC_FOLDLEVELBASE + 1;
281 		else
282 			lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;
283 	} else {
284 		lev = SC_FOLDLEVELBASE;
285 	}
286 	int flagsNext = styler.LevelAt(lineCurrent);
287 	styler.SetLevel(lineCurrent, lev | flagsNext & ~SC_FOLDLEVELNUMBERMASK);
288 }
289 
290 LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);
291