]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexOthers.cxx
f188722ff208fb7396934517a686dbbf71188970
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexOthers.cxx
1 // Scintilla source code edit control
2 /** @file LexOthers.cxx
3 ** Lexers for batch files, diff results, properties files, make files and error lists.
4 ** Also lexer for LaTeX documents.
5 **/
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 static inline bool AtEOL(Accessor &styler, unsigned int i) {
24 return (styler[i] == '\n') ||
25 ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
26 }
27
28 static void ColouriseBatchLine(
29 char *lineBuffer,
30 unsigned int lengthLine,
31 unsigned int startLine,
32 unsigned int endPos,
33 WordList &keywords,
34 Accessor &styler) {
35
36 unsigned int i = 0;
37 unsigned int state = SCE_BAT_DEFAULT;
38
39 while ((i < lengthLine) && isspacechar(lineBuffer[i])) { // Skip initial spaces
40 i++;
41 }
42 if (lineBuffer[i] == '@') { // Hide command (ECHO OFF)
43 styler.ColourTo(startLine + i, SCE_BAT_HIDE);
44 i++;
45 while ((i < lengthLine) && isspacechar(lineBuffer[i])) { // Skip next spaces
46 i++;
47 }
48 }
49 if (lineBuffer[i] == ':') {
50 // Label
51 if (lineBuffer[i + 1] == ':') {
52 // :: is a fake label, similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm
53 styler.ColourTo(endPos, SCE_BAT_COMMENT);
54 } else { // Real label
55 styler.ColourTo(endPos, SCE_BAT_LABEL);
56 }
57 } else {
58 // Check if initial word is a keyword
59 char wordBuffer[21];
60 unsigned int wbl = 0, offset = i;
61 // Copy word in buffer
62 for (; offset < lengthLine && wbl < 20 &&
63 !isspacechar(lineBuffer[offset]); wbl++, offset++) {
64 wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset]));
65 }
66 wordBuffer[wbl] = '\0';
67 // Check if it is a comment
68 if (CompareCaseInsensitive(wordBuffer, "rem") == 0) {
69 styler.ColourTo(endPos, SCE_BAT_COMMENT);
70 return ;
71 }
72 // Check if it is in the list
73 if (keywords.InList(wordBuffer)) {
74 styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); // Regular keyword
75 } else {
76 // Search end of word (can be a long path)
77 while (offset < lengthLine &&
78 !isspacechar(lineBuffer[offset])) {
79 offset++;
80 }
81 styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); // External command / program
82 }
83 // Remainder of the line: colourise the variables.
84
85 while (offset < lengthLine) {
86 if (state == SCE_BAT_DEFAULT && lineBuffer[offset] == '%') {
87 styler.ColourTo(startLine + offset - 1, state);
88 if (isdigit(lineBuffer[offset + 1])) {
89 styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER);
90 offset += 2;
91 } else if (lineBuffer[offset + 1] == '%' &&
92 !isspacechar(lineBuffer[offset + 2])) {
93 // Should be safe, as there is CRLF at the end of the line...
94 styler.ColourTo(startLine + offset + 2, SCE_BAT_IDENTIFIER);
95 offset += 3;
96 } else {
97 state = SCE_BAT_IDENTIFIER;
98 }
99 } else if (state == SCE_BAT_IDENTIFIER && lineBuffer[offset] == '%') {
100 styler.ColourTo(startLine + offset, state);
101 state = SCE_BAT_DEFAULT;
102 } else if (state == SCE_BAT_DEFAULT &&
103 (lineBuffer[offset] == '*' ||
104 lineBuffer[offset] == '?' ||
105 lineBuffer[offset] == '=' ||
106 lineBuffer[offset] == '<' ||
107 lineBuffer[offset] == '>' ||
108 lineBuffer[offset] == '|')) {
109 styler.ColourTo(startLine + offset - 1, state);
110 styler.ColourTo(startLine + offset, SCE_BAT_OPERATOR);
111 }
112 offset++;
113 }
114 // if (endPos > startLine + offset - 1) {
115 styler.ColourTo(endPos, SCE_BAT_DEFAULT); // Remainder of line, currently not lexed
116 // }
117 }
118
119 }
120 // ToDo: (not necessarily at beginning of line) GOTO, [IF] NOT, ERRORLEVEL
121 // IF [NO] (test) (command) -- test is EXIST (filename) | (string1)==(string2) | ERRORLEVEL (number)
122 // FOR %%(variable) IN (set) DO (command) -- variable is [a-zA-Z] -- eg for %%X in (*.txt) do type %%X
123 // ToDo: %n (parameters), %EnvironmentVariable% colourising
124 // ToDo: Colourise = > >> < | "
125
126 static void ColouriseBatchDoc(
127 unsigned int startPos,
128 int length,
129 int /*initStyle*/,
130 WordList *keywordlists[],
131 Accessor &styler) {
132
133 char lineBuffer[1024];
134 WordList &keywords = *keywordlists[0];
135
136 styler.StartAt(startPos);
137 styler.StartSegment(startPos);
138 unsigned int linePos = 0;
139 unsigned int startLine = startPos;
140 for (unsigned int i = startPos; i < startPos + length; i++) {
141 lineBuffer[linePos++] = styler[i];
142 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
143 // End of line (or of line buffer) met, colourise it
144 lineBuffer[linePos] = '\0';
145 ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywords, styler);
146 linePos = 0;
147 startLine = i + 1;
148 }
149 }
150 if (linePos > 0) { // Last line does not have ending characters
151 ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1,
152 keywords, styler);
153 }
154 }
155
156 static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) {
157 // It is needed to remember the current state to recognize starting
158 // comment lines before the first "diff " or "--- ". If a real
159 // difference starts then each line starting with ' ' is a whitespace
160 // otherwise it is considered a comment (Only in..., Binary file...)
161 if (0 == strncmp(lineBuffer, "diff ", 3)) {
162 styler.ColourTo(endLine, 2);
163 } else if (0 == strncmp(lineBuffer, "--- ", 3)) {
164 styler.ColourTo(endLine, 3);
165 } else if (0 == strncmp(lineBuffer, "+++ ", 3)) {
166 styler.ColourTo(endLine, 3);
167 } else if (lineBuffer[0] == '@') {
168 styler.ColourTo(endLine, 4);
169 } else if (lineBuffer[0] == '-') {
170 styler.ColourTo(endLine, 5);
171 } else if (lineBuffer[0] == '+') {
172 styler.ColourTo(endLine, 6);
173 } else if (lineBuffer[0] != ' ') {
174 styler.ColourTo(endLine, 1);
175 } else {
176 styler.ColourTo(endLine, 0);
177 }
178 }
179
180 static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
181 char lineBuffer[1024];
182 styler.StartAt(startPos);
183 styler.StartSegment(startPos);
184 unsigned int linePos = 0;
185 for (unsigned int i = startPos; i < startPos + length; i++) {
186 lineBuffer[linePos++] = styler[i];
187 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
188 // End of line (or of line buffer) met, colourise it
189 lineBuffer[linePos] = '\0';
190 ColouriseDiffLine(lineBuffer, i, styler);
191 linePos = 0;
192 }
193 }
194 if (linePos > 0) { // Last line does not have ending characters
195 ColouriseDiffLine(lineBuffer, startPos + length - 1, styler);
196 }
197 }
198
199 static void ColourisePropsLine(
200 char *lineBuffer,
201 unsigned int lengthLine,
202 unsigned int startLine,
203 unsigned int endPos,
204 Accessor &styler) {
205
206 unsigned int i = 0;
207 while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces
208 i++;
209 if (i < lengthLine) {
210 if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') {
211 styler.ColourTo(endPos, 1);
212 } else if (lineBuffer[i] == '[') {
213 styler.ColourTo(endPos, 2);
214 } else if (lineBuffer[i] == '@') {
215 styler.ColourTo(startLine + i, 4);
216 if (lineBuffer[++i] == '=')
217 styler.ColourTo(startLine + i, 3);
218 styler.ColourTo(endPos, 0);
219 } else {
220 // Search for the '=' character
221 while ((i < lengthLine) && (lineBuffer[i] != '='))
222 i++;
223 if ((i < lengthLine) && (lineBuffer[i] == '=')) {
224 styler.ColourTo(startLine + i - 1, 0);
225 styler.ColourTo(startLine + i, 3);
226 styler.ColourTo(endPos, 0);
227 } else {
228 styler.ColourTo(endPos, 0);
229 }
230 }
231 } else {
232 styler.ColourTo(endPos, 0);
233 }
234 }
235
236 static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
237 char lineBuffer[1024];
238 styler.StartAt(startPos);
239 styler.StartSegment(startPos);
240 unsigned int linePos = 0;
241 unsigned int startLine = startPos;
242 for (unsigned int i = startPos; i < startPos + length; i++) {
243 lineBuffer[linePos++] = styler[i];
244 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
245 // End of line (or of line buffer) met, colourise it
246 lineBuffer[linePos] = '\0';
247 ColourisePropsLine(lineBuffer, linePos, startLine, i, styler);
248 linePos = 0;
249 startLine = i + 1;
250 }
251 }
252 if (linePos > 0) { // Last line does not have ending characters
253 ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);
254 }
255 }
256
257 static void ColouriseMakeLine(
258 char *lineBuffer,
259 unsigned int lengthLine,
260 unsigned int startLine,
261 unsigned int endPos,
262 Accessor &styler) {
263
264 unsigned int i = 0;
265 unsigned int lastNonSpace = 0;
266 unsigned int state = SCE_MAKE_DEFAULT;
267 bool bSpecial = false;
268 // Skip initial spaces
269 while ((i < lengthLine) && isspacechar(lineBuffer[i])) {
270 i++;
271 }
272 if (lineBuffer[i] == '#') { // Comment
273 styler.ColourTo(endPos, SCE_MAKE_COMMENT);
274 return;
275 }
276 if (lineBuffer[i] == '!') { // Special directive
277 styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR);
278 return;
279 }
280 while (i < lengthLine) {
281 if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') {
282 styler.ColourTo(startLine + i - 1, state);
283 state = SCE_MAKE_IDENTIFIER;
284 } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') {
285 styler.ColourTo(startLine + i, state);
286 state = SCE_MAKE_DEFAULT;
287 }
288 if (!bSpecial) {
289 if (lineBuffer[i] == ':') {
290 // We should check that no colouring was made since the beginning of the line,
291 // to avoid colouring stuff like /OUT:file
292 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);
293 styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
294 styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
295 bSpecial = true; // Only react to the first ':' of the line
296 state = SCE_MAKE_DEFAULT;
297 } else if (lineBuffer[i] == '=') {
298 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);
299 styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
300 styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
301 bSpecial = true; // Only react to the first '=' of the line
302 state = SCE_MAKE_DEFAULT;
303 }
304 }
305 if (!isspacechar(lineBuffer[i])) {
306 lastNonSpace = i;
307 }
308 i++;
309 }
310 if (state == SCE_MAKE_IDENTIFIER) {
311 styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended
312 } else {
313 styler.ColourTo(endPos, SCE_MAKE_DEFAULT);
314 }
315 }
316
317 static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
318 char lineBuffer[1024];
319 styler.StartAt(startPos);
320 styler.StartSegment(startPos);
321 unsigned int linePos = 0;
322 unsigned int startLine = startPos;
323 for (unsigned int i = startPos; i < startPos + length; i++) {
324 lineBuffer[linePos++] = styler[i];
325 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
326 // End of line (or of line buffer) met, colourise it
327 lineBuffer[linePos] = '\0';
328 ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler);
329 linePos = 0;
330 startLine = i + 1;
331 }
332 }
333 if (linePos > 0) { // Last line does not have ending characters
334 ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);
335 }
336 }
337
338 static void ColouriseErrorListLine(
339 char *lineBuffer,
340 unsigned int lengthLine,
341 // unsigned int startLine,
342 unsigned int endPos,
343 Accessor &styler) {
344 if (lineBuffer[0] == '>') {
345 // Command or return status
346 styler.ColourTo(endPos, SCE_ERR_CMD);
347 } else if (lineBuffer[0] == '!') {
348 styler.ColourTo(endPos, SCE_ERR_DIFF_CHANGED);
349 } else if (lineBuffer[0] == '+') {
350 styler.ColourTo(endPos, SCE_ERR_DIFF_ADDITION);
351 } else if (lineBuffer[0] == '-' && lineBuffer[1] == '-' && lineBuffer[2] == '-') {
352 styler.ColourTo(endPos, SCE_ERR_DIFF_MESSAGE);
353 } else if (lineBuffer[0] == '-') {
354 styler.ColourTo(endPos, SCE_ERR_DIFF_DELETION);
355 } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) {
356 styler.ColourTo(endPos, SCE_ERR_PYTHON);
357 } else if (0 == strncmp(lineBuffer, "Error ", strlen("Error "))) {
358 // Borland error message
359 styler.ColourTo(endPos, SCE_ERR_BORLAND);
360 } else if (0 == strncmp(lineBuffer, "Warning ", strlen("Warning "))) {
361 // Borland warning message
362 styler.ColourTo(endPos, SCE_ERR_BORLAND);
363 } else if (strstr(lineBuffer, "at line " ) &&
364 (strstr(lineBuffer, "at line " ) < (lineBuffer + lengthLine)) &&
365 strstr(lineBuffer, "file ") &&
366 (strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) {
367 // Lua error message
368 styler.ColourTo(endPos, SCE_ERR_LUA);
369 } else if (strstr(lineBuffer, " at " ) &&
370 (strstr(lineBuffer, " at " ) < (lineBuffer + lengthLine)) &&
371 strstr(lineBuffer, " line ") &&
372 (strstr(lineBuffer, " line ") < (lineBuffer + lengthLine))) {
373 // perl error message
374 styler.ColourTo(endPos, SCE_ERR_PERL);
375 } else if ((memcmp(lineBuffer, " at ", 6) == 0) &&
376 strstr(lineBuffer, ":line ")) {
377 // A .NET traceback
378 styler.ColourTo(endPos, SCE_ERR_NET);
379 } else {
380 // Look for <filename>:<line>:message
381 // Look for <filename>(line)message
382 // Look for <filename>(line,pos)message
383 int state = 0;
384 for (unsigned int i = 0; i < lengthLine; i++) {
385 if ((state == 0) && (lineBuffer[i] == ':') && isdigit(lineBuffer[i + 1])) {
386 state = 1;
387 } else if ((state == 0) && (lineBuffer[i] == '(')) {
388 state = 10;
389 } else if ((state == 1) && isdigit(lineBuffer[i])) {
390 state = 2;
391 } else if ((state == 2) && (lineBuffer[i] == ':')) {
392 state = 3;
393 break;
394 } else if ((state == 2) && !isdigit(lineBuffer[i])) {
395 state = 99;
396 } else if ((state == 10) && isdigit(lineBuffer[i])) {
397 state = 11;
398 } else if ((state == 11) && (lineBuffer[i] == ',')) {
399 state = 14;
400 } else if ((state == 11) && (lineBuffer[i] == ')')) {
401 state = 12;
402 } else if ((state == 12) && (lineBuffer[i] == ':')) {
403 state = 13;
404 } else if ((state == 14) && (lineBuffer[i] == ')')) {
405 state = 15;
406 break;
407 } else if (((state == 11) || (state == 14)) && !((lineBuffer[i] == ' ') || isdigit(lineBuffer[i]))) {
408 state = 99;
409 }
410 }
411 if (state == 3) {
412 styler.ColourTo(endPos, SCE_ERR_GCC);
413 } else if ((state == 13) || (state == 14) || (state == 15)) {
414 styler.ColourTo(endPos, SCE_ERR_MS);
415 } else {
416 styler.ColourTo(endPos, SCE_ERR_DEFAULT);
417 }
418 }
419 }
420
421 static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
422 char lineBuffer[1024];
423 styler.StartAt(startPos);
424 styler.StartSegment(startPos);
425 unsigned int linePos = 0;
426 for (unsigned int i = startPos; i < startPos + length; i++) {
427 lineBuffer[linePos++] = styler[i];
428 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
429 // End of line (or of line buffer) met, colourise it
430 lineBuffer[linePos] = '\0';
431 ColouriseErrorListLine(lineBuffer, linePos, i, styler);
432 linePos = 0;
433 }
434 }
435 if (linePos > 0) { // Last line does not have ending characters
436 ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler);
437 }
438 }
439
440 static int isSpecial(char s) {
441 return (s == '\\') || (s == ',') || (s == ';') || (s == '\'') || (s == ' ') ||
442 (s == '\"') || (s == '`') || (s == '^') || (s == '~');
443 }
444
445 static int isTag(int start, Accessor &styler) {
446 char s[6];
447 unsigned int i = 0, e = 1;
448 while (i < 5 && e) {
449 s[i] = styler[start + i];
450 i++;
451 e = styler[start + i] != '{';
452 }
453 s[i] = '\0';
454 return (strcmp(s, "begin") == 0) || (strcmp(s, "end") == 0);
455 }
456
457 static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle,
458 WordList *[], Accessor &styler) {
459
460 styler.StartAt(startPos);
461
462 int state = initStyle;
463 char chNext = styler[startPos];
464 styler.StartSegment(startPos);
465 int lengthDoc = startPos + length;
466
467 for (int i = startPos; i < lengthDoc; i++) {
468 char ch = chNext;
469 chNext = styler.SafeGetCharAt(i + 1);
470
471 if (styler.IsLeadByte(ch)) {
472 chNext = styler.SafeGetCharAt(i + 2);
473 i++;
474 continue;
475 }
476 switch (state) {
477 case SCE_L_DEFAULT :
478 switch (ch) {
479 case '\\' :
480 styler.ColourTo(i - 1, state);
481 if (isSpecial(styler[i + 1])) {
482 styler.ColourTo(i + 1, SCE_L_COMMAND);
483 i++;
484 chNext = styler.SafeGetCharAt(i + 1);
485 } else {
486 if (isTag(i + 1, styler))
487 state = SCE_L_TAG;
488 else
489 state = SCE_L_COMMAND;
490 }
491 break;
492 case '$' :
493 styler.ColourTo(i - 1, state);
494 state = SCE_L_MATH;
495 if (chNext == '$') {
496 i++;
497 chNext = styler.SafeGetCharAt(i + 1);
498 }
499 break;
500 case '%' :
501 styler.ColourTo(i - 1, state);
502 state = SCE_L_COMMENT;
503 break;
504 }
505 break;
506 case SCE_L_COMMAND :
507 if (chNext == '[' || chNext == '{' || chNext == '}' ||
508 chNext == ' ' || chNext == '\r' || chNext == '\n') {
509 styler.ColourTo(i, state);
510 state = SCE_L_DEFAULT;
511 i++;
512 chNext = styler.SafeGetCharAt(i + 1);
513 }
514 break;
515 case SCE_L_TAG :
516 if (ch == '}') {
517 styler.ColourTo(i, state);
518 state = SCE_L_DEFAULT;
519 }
520 break;
521 case SCE_L_MATH :
522 if (ch == '$') {
523 if (chNext == '$') {
524 i++;
525 chNext = styler.SafeGetCharAt(i + 1);
526 }
527 styler.ColourTo(i, state);
528 state = SCE_L_DEFAULT;
529 }
530 break;
531 case SCE_L_COMMENT :
532 if (ch == '\r' || ch == '\n') {
533 styler.ColourTo(i - 1, state);
534 state = SCE_L_DEFAULT;
535 }
536 }
537 }
538 styler.ColourTo(lengthDoc, state);
539 }
540
541 LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch");
542 LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff");
543 LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props");
544 LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile");
545 LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist");
546 LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex");