OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexOthers.cxx
1 // Scintilla source code edit control\r
2 /** @file LexOthers.cxx\r
3  ** Lexers for batch files, diff results, properties files, make files and error lists.\r
4  ** Also lexer for LaTeX documents.\r
5  **/\r
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>\r
7 // The License.txt file describes the conditions under which this software may be distributed.\r
8 \r
9 #include <stdlib.h>\r
10 #include <string.h>\r
11 #include <ctype.h>\r
12 #include <stdio.h>\r
13 #include <stdarg.h>\r
14 \r
15 #include "Platform.h"\r
16 \r
17 #include "PropSet.h"\r
18 #include "Accessor.h"\r
19 #include "KeyWords.h"\r
20 #include "Scintilla.h"\r
21 #include "SciLexer.h"\r
22 \r
23 #ifdef SCI_NAMESPACE\r
24 using namespace Scintilla;\r
25 #endif\r
26 \r
27 static bool strstart(const char *haystack, const char *needle) {\r
28         return strncmp(haystack, needle, strlen(needle)) == 0;\r
29 }\r
30 \r
31 static bool Is0To9(char ch) {\r
32         return (ch >= '0') && (ch <= '9');\r
33 }\r
34 \r
35 static bool Is1To9(char ch) {\r
36         return (ch >= '1') && (ch <= '9');\r
37 }\r
38 \r
39 static inline bool AtEOL(Accessor &styler, unsigned int i) {\r
40         return (styler[i] == '\n') ||\r
41                ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));\r
42 }\r
43 \r
44 // Tests for BATCH Operators\r
45 static bool IsBOperator(char ch) {\r
46         return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') ||\r
47                 (ch == '|') || (ch == '?') || (ch == '*');\r
48 }\r
49 \r
50 // Tests for BATCH Separators\r
51 static bool IsBSeparator(char ch) {\r
52         return (ch == '\\') || (ch == '.') || (ch == ';') ||\r
53                 (ch == '\"') || (ch == '\'') || (ch == '/') || (ch == ')');\r
54 }\r
55 \r
56 static void ColouriseBatchLine(\r
57     char *lineBuffer,\r
58     unsigned int lengthLine,\r
59     unsigned int startLine,\r
60     unsigned int endPos,\r
61     WordList *keywordlists[],\r
62     Accessor &styler) {\r
63 \r
64         unsigned int offset = 0;        // Line Buffer Offset\r
65         unsigned int cmdLoc;            // External Command / Program Location\r
66         char wordBuffer[81];            // Word Buffer - large to catch long paths\r
67         unsigned int wbl;               // Word Buffer Length\r
68         unsigned int wbo;               // Word Buffer Offset - also Special Keyword Buffer Length\r
69         WordList &keywords = *keywordlists[0];      // Internal Commands\r
70         WordList &keywords2 = *keywordlists[1];     // External Commands (optional)\r
71 \r
72         // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords\r
73         //   Toggling Regular Keyword Checking off improves readability\r
74         // Other Regular Keywords and External Commands / Programs might also benefit from toggling\r
75         //   Need a more robust algorithm to properly toggle Regular Keyword Checking\r
76         bool continueProcessing = true; // Used to toggle Regular Keyword Checking\r
77         // Special Keywords are those that allow certain characters without whitespace after the command\r
78         // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path=\r
79         // Special Keyword Buffer used to determine if the first n characters is a Keyword\r
80         char sKeywordBuffer[10];        // Special Keyword Buffer\r
81         bool sKeywordFound;             // Exit Special Keyword for-loop if found\r
82 \r
83         // Skip initial spaces\r
84         while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {\r
85                 offset++;\r
86         }\r
87         // Colorize Default Text\r
88         styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);\r
89         // Set External Command / Program Location\r
90         cmdLoc = offset;\r
91 \r
92         // Check for Fake Label (Comment) or Real Label - return if found\r
93         if (lineBuffer[offset] == ':') {\r
94                 if (lineBuffer[offset + 1] == ':') {\r
95                         // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm\r
96                         styler.ColourTo(endPos, SCE_BAT_COMMENT);\r
97                 } else {\r
98                         // Colorize Real Label\r
99                         styler.ColourTo(endPos, SCE_BAT_LABEL);\r
100                 }\r
101                 return;\r
102         // Check for Drive Change (Drive Change is internal command) - return if found\r
103         } else if ((isalpha(lineBuffer[offset])) &&\r
104                 (lineBuffer[offset + 1] == ':') &&\r
105                 ((isspacechar(lineBuffer[offset + 2])) ||\r
106                 (((lineBuffer[offset + 2] == '\\')) &&\r
107                 (isspacechar(lineBuffer[offset + 3]))))) {\r
108                 // Colorize Regular Keyword\r
109                 styler.ColourTo(endPos, SCE_BAT_WORD);\r
110                 return;\r
111         }\r
112 \r
113         // Check for Hide Command (@ECHO OFF/ON)\r
114         if (lineBuffer[offset] == '@') {\r
115                 styler.ColourTo(startLine + offset, SCE_BAT_HIDE);\r
116                 offset++;\r
117         }\r
118         // Skip next spaces\r
119         while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {\r
120                 offset++;\r
121         }\r
122 \r
123         // Read remainder of line word-at-a-time or remainder-of-word-at-a-time\r
124         while (offset < lengthLine) {\r
125                 if (offset > startLine) {\r
126                         // Colorize Default Text\r
127                         styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);\r
128                 }\r
129                 // Copy word from Line Buffer into Word Buffer\r
130                 wbl = 0;\r
131                 for (; offset < lengthLine && wbl < 80 &&\r
132                         !isspacechar(lineBuffer[offset]); wbl++, offset++) {\r
133                         wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset]));\r
134                 }\r
135                 wordBuffer[wbl] = '\0';\r
136                 wbo = 0;\r
137 \r
138                 // Check for Comment - return if found\r
139                 if (CompareCaseInsensitive(wordBuffer, "rem") == 0) {\r
140                         styler.ColourTo(endPos, SCE_BAT_COMMENT);\r
141                         return;\r
142                 }\r
143                 // Check for Separator\r
144                 if (IsBSeparator(wordBuffer[0])) {\r
145                         // Check for External Command / Program\r
146                         if ((cmdLoc == offset - wbl) &&\r
147                                 ((wordBuffer[0] == ':') ||\r
148                                 (wordBuffer[0] == '\\') ||\r
149                                 (wordBuffer[0] == '.'))) {\r
150                                 // Reset Offset to re-process remainder of word\r
151                                 offset -= (wbl - 1);\r
152                                 // Colorize External Command / Program\r
153                                 if (!keywords2) {\r
154                                         styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);\r
155                                 } else if (keywords2.InList(wordBuffer)) {\r
156                                         styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);\r
157                                 } else {\r
158                                         styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);\r
159                                 }\r
160                                 // Reset External Command / Program Location\r
161                                 cmdLoc = offset;\r
162                         } else {\r
163                                 // Reset Offset to re-process remainder of word\r
164                                 offset -= (wbl - 1);\r
165                                 // Colorize Default Text\r
166                                 styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);\r
167                         }\r
168                 // Check for Regular Keyword in list\r
169                 } else if ((keywords.InList(wordBuffer)) &&\r
170                         (continueProcessing)) {\r
171                         // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking\r
172                         if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) ||\r
173                                 (CompareCaseInsensitive(wordBuffer, "goto") == 0) ||\r
174                                 (CompareCaseInsensitive(wordBuffer, "prompt") == 0) ||\r
175                                 (CompareCaseInsensitive(wordBuffer, "set") == 0)) {\r
176                                 continueProcessing = false;\r
177                         }\r
178                         // Identify External Command / Program Location for ERRORLEVEL, and EXIST\r
179                         if ((CompareCaseInsensitive(wordBuffer, "errorlevel") == 0) ||\r
180                                 (CompareCaseInsensitive(wordBuffer, "exist") == 0)) {\r
181                                 // Reset External Command / Program Location\r
182                                 cmdLoc = offset;\r
183                                 // Skip next spaces\r
184                                 while ((cmdLoc < lengthLine) &&\r
185                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
186                                         cmdLoc++;\r
187                                 }\r
188                                 // Skip comparison\r
189                                 while ((cmdLoc < lengthLine) &&\r
190                                         (!isspacechar(lineBuffer[cmdLoc]))) {\r
191                                         cmdLoc++;\r
192                                 }\r
193                                 // Skip next spaces\r
194                                 while ((cmdLoc < lengthLine) &&\r
195                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
196                                         cmdLoc++;\r
197                                 }\r
198                         // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH\r
199                         } else if ((CompareCaseInsensitive(wordBuffer, "call") == 0) ||\r
200                                 (CompareCaseInsensitive(wordBuffer, "do") == 0) ||\r
201                                 (CompareCaseInsensitive(wordBuffer, "loadhigh") == 0) ||\r
202                                 (CompareCaseInsensitive(wordBuffer, "lh") == 0)) {\r
203                                 // Reset External Command / Program Location\r
204                                 cmdLoc = offset;\r
205                                 // Skip next spaces\r
206                                 while ((cmdLoc < lengthLine) &&\r
207                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
208                                         cmdLoc++;\r
209                                 }\r
210                         }\r
211                         // Colorize Regular keyword\r
212                         styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD);\r
213                         // No need to Reset Offset\r
214                 // Check for Special Keyword in list, External Command / Program, or Default Text\r
215                 } else if ((wordBuffer[0] != '%') &&\r
216                         (!IsBOperator(wordBuffer[0])) &&\r
217                         (continueProcessing)) {\r
218                         // Check for Special Keyword\r
219                         //     Affected Commands are in Length range 2-6\r
220                         //     Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected\r
221                         sKeywordFound = false;\r
222                         for (unsigned int keywordLength = 2; keywordLength < wbl && keywordLength < 7 && !sKeywordFound; keywordLength++) {\r
223                                 wbo = 0;\r
224                                 // Copy Keyword Length from Word Buffer into Special Keyword Buffer\r
225                                 for (; wbo < keywordLength; wbo++) {\r
226                                         sKeywordBuffer[wbo] = static_cast<char>(wordBuffer[wbo]);\r
227                                 }\r
228                                 sKeywordBuffer[wbo] = '\0';\r
229                                 // Check for Special Keyword in list\r
230                                 if ((keywords.InList(sKeywordBuffer)) &&\r
231                                         ((IsBOperator(wordBuffer[wbo])) ||\r
232                                         (IsBSeparator(wordBuffer[wbo])))) {\r
233                                         sKeywordFound = true;\r
234                                         // ECHO requires no further Regular Keyword Checking\r
235                                         if (CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) {\r
236                                                 continueProcessing = false;\r
237                                         }\r
238                                         // Colorize Special Keyword as Regular Keyword\r
239                                         styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD);\r
240                                         // Reset Offset to re-process remainder of word\r
241                                         offset -= (wbl - wbo);\r
242                                 }\r
243                         }\r
244                         // Check for External Command / Program or Default Text\r
245                         if (!sKeywordFound) {\r
246                                 wbo = 0;\r
247                                 // Check for External Command / Program\r
248                                 if (cmdLoc == offset - wbl) {\r
249                                         // Read up to %, Operator or Separator\r
250                                         while ((wbo < wbl) &&\r
251                                                 (wordBuffer[wbo] != '%') &&\r
252                                                 (!IsBOperator(wordBuffer[wbo])) &&\r
253                                                 (!IsBSeparator(wordBuffer[wbo]))) {\r
254                                                 wbo++;\r
255                                         }\r
256                                         // Reset External Command / Program Location\r
257                                         cmdLoc = offset - (wbl - wbo);\r
258                                         // Reset Offset to re-process remainder of word\r
259                                         offset -= (wbl - wbo);\r
260                                         // CHOICE requires no further Regular Keyword Checking\r
261                                         if (CompareCaseInsensitive(wordBuffer, "choice") == 0) {\r
262                                                 continueProcessing = false;\r
263                                         }\r
264                                         // Check for START (and its switches) - What follows is External Command \ Program\r
265                                         if (CompareCaseInsensitive(wordBuffer, "start") == 0) {\r
266                                                 // Reset External Command / Program Location\r
267                                                 cmdLoc = offset;\r
268                                                 // Skip next spaces\r
269                                                 while ((cmdLoc < lengthLine) &&\r
270                                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
271                                                         cmdLoc++;\r
272                                                 }\r
273                                                 // Reset External Command / Program Location if command switch detected\r
274                                                 if (lineBuffer[cmdLoc] == '/') {\r
275                                                         // Skip command switch\r
276                                                         while ((cmdLoc < lengthLine) &&\r
277                                                                 (!isspacechar(lineBuffer[cmdLoc]))) {\r
278                                                                 cmdLoc++;\r
279                                                         }\r
280                                                         // Skip next spaces\r
281                                                         while ((cmdLoc < lengthLine) &&\r
282                                                                 (isspacechar(lineBuffer[cmdLoc]))) {\r
283                                                                 cmdLoc++;\r
284                                                         }\r
285                                                 }\r
286                                         }\r
287                                         // Colorize External Command / Program\r
288                                         if (!keywords2) {\r
289                                                 styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);\r
290                                         } else if (keywords2.InList(wordBuffer)) {\r
291                                                 styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);\r
292                                         } else {\r
293                                                 styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);\r
294                                         }\r
295                                         // No need to Reset Offset\r
296                                 // Check for Default Text\r
297                                 } else {\r
298                                         // Read up to %, Operator or Separator\r
299                                         while ((wbo < wbl) &&\r
300                                                 (wordBuffer[wbo] != '%') &&\r
301                                                 (!IsBOperator(wordBuffer[wbo])) &&\r
302                                                 (!IsBSeparator(wordBuffer[wbo]))) {\r
303                                                 wbo++;\r
304                                         }\r
305                                         // Colorize Default Text\r
306                                         styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);\r
307                                         // Reset Offset to re-process remainder of word\r
308                                         offset -= (wbl - wbo);\r
309                                 }\r
310                         }\r
311                 // Check for Argument  (%n), Environment Variable (%x...%) or Local Variable (%%a)\r
312                 } else if (wordBuffer[0] == '%') {\r
313                         // Colorize Default Text\r
314                         styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);\r
315                         wbo++;\r
316                         // Search to end of word for second % (can be a long path)\r
317                         while ((wbo < wbl) &&\r
318                                 (wordBuffer[wbo] != '%') &&\r
319                                 (!IsBOperator(wordBuffer[wbo])) &&\r
320                                 (!IsBSeparator(wordBuffer[wbo]))) {\r
321                                 wbo++;\r
322                         }\r
323                         // Check for Argument (%n) or (%*)\r
324                         if (((Is0To9(wordBuffer[1])) || (wordBuffer[1] == '*')) &&\r
325                                 (wordBuffer[wbo] != '%')) {\r
326                                 // Check for External Command / Program\r
327                                 if (cmdLoc == offset - wbl) {\r
328                                         cmdLoc = offset - (wbl - 2);\r
329                                 }\r
330                                 // Colorize Argument\r
331                                 styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER);\r
332                                 // Reset Offset to re-process remainder of word\r
333                                 offset -= (wbl - 2);\r
334                         // Check for Expanded Argument (%~...) / Variable (%%~...)\r
335                         } else if (((wbl > 1) && (wordBuffer[1] == '~')) ||\r
336                                 ((wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] == '~'))) {\r
337                                 // Check for External Command / Program\r
338                                 if (cmdLoc == offset - wbl) {\r
339                                         cmdLoc = offset - (wbl - wbo);\r
340                                 }\r
341                                 // Colorize Expanded Argument / Variable\r
342                                 styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);\r
343                                 // Reset Offset to re-process remainder of word\r
344                                 offset -= (wbl - wbo);\r
345                         // Check for Environment Variable (%x...%)\r
346                         } else if ((wordBuffer[1] != '%') &&\r
347                                 (wordBuffer[wbo] == '%')) {\r
348                                 wbo++;\r
349                                 // Check for External Command / Program\r
350                                 if (cmdLoc == offset - wbl) {\r
351                                         cmdLoc = offset - (wbl - wbo);\r
352                                 }\r
353                                 // Colorize Environment Variable\r
354                                 styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);\r
355                                 // Reset Offset to re-process remainder of word\r
356                                 offset -= (wbl - wbo);\r
357                         // Check for Local Variable (%%a)\r
358                         } else if (\r
359                                 (wbl > 2) &&\r
360                                 (wordBuffer[1] == '%') &&\r
361                                 (wordBuffer[2] != '%') &&\r
362                                 (!IsBOperator(wordBuffer[2])) &&\r
363                                 (!IsBSeparator(wordBuffer[2]))) {\r
364                                 // Check for External Command / Program\r
365                                 if (cmdLoc == offset - wbl) {\r
366                                         cmdLoc = offset - (wbl - 3);\r
367                                 }\r
368                                 // Colorize Local Variable\r
369                                 styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER);\r
370                                 // Reset Offset to re-process remainder of word\r
371                                 offset -= (wbl - 3);\r
372                         }\r
373                 // Check for Operator\r
374                 } else if (IsBOperator(wordBuffer[0])) {\r
375                         // Colorize Default Text\r
376                         styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);\r
377                         // Check for Comparison Operator\r
378                         if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) {\r
379                                 // Identify External Command / Program Location for IF\r
380                                 cmdLoc = offset;\r
381                                 // Skip next spaces\r
382                                 while ((cmdLoc < lengthLine) &&\r
383                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
384                                         cmdLoc++;\r
385                                 }\r
386                                 // Colorize Comparison Operator\r
387                                 styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR);\r
388                                 // Reset Offset to re-process remainder of word\r
389                                 offset -= (wbl - 2);\r
390                         // Check for Pipe Operator\r
391                         } else if (wordBuffer[0] == '|') {\r
392                                 // Reset External Command / Program Location\r
393                                 cmdLoc = offset - wbl + 1;\r
394                                 // Skip next spaces\r
395                                 while ((cmdLoc < lengthLine) &&\r
396                                         (isspacechar(lineBuffer[cmdLoc]))) {\r
397                                         cmdLoc++;\r
398                                 }\r
399                                 // Colorize Pipe Operator\r
400                                 styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR);\r
401                                 // Reset Offset to re-process remainder of word\r
402                                 offset -= (wbl - 1);\r
403                         // Check for Other Operator\r
404                         } else {\r
405                                 // Check for > Operator\r
406                                 if (wordBuffer[0] == '>') {\r
407                                         // Turn Keyword and External Command / Program checking back on\r
408                                         continueProcessing = true;\r
409                                 }\r
410                                 // Colorize Other Operator\r
411                                 styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR);\r
412                                 // Reset Offset to re-process remainder of word\r
413                                 offset -= (wbl - 1);\r
414                         }\r
415                 // Check for Default Text\r
416                 } else {\r
417                         // Read up to %, Operator or Separator\r
418                         while ((wbo < wbl) &&\r
419                                 (wordBuffer[wbo] != '%') &&\r
420                                 (!IsBOperator(wordBuffer[wbo])) &&\r
421                                 (!IsBSeparator(wordBuffer[wbo]))) {\r
422                                 wbo++;\r
423                         }\r
424                         // Colorize Default Text\r
425                         styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT);\r
426                         // Reset Offset to re-process remainder of word\r
427                         offset -= (wbl - wbo);\r
428                 }\r
429                 // Skip next spaces - nothing happens if Offset was Reset\r
430                 while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {\r
431                         offset++;\r
432                 }\r
433         }\r
434         // Colorize Default Text for remainder of line - currently not lexed\r
435         styler.ColourTo(endPos, SCE_BAT_DEFAULT);\r
436 }\r
437 \r
438 static void ColouriseBatchDoc(\r
439     unsigned int startPos,\r
440     int length,\r
441     int /*initStyle*/,\r
442     WordList *keywordlists[],\r
443     Accessor &styler) {\r
444 \r
445         char lineBuffer[1024];\r
446 \r
447         styler.StartAt(startPos);\r
448         styler.StartSegment(startPos);\r
449         unsigned int linePos = 0;\r
450         unsigned int startLine = startPos;\r
451         for (unsigned int i = startPos; i < startPos + length; i++) {\r
452                 lineBuffer[linePos++] = styler[i];\r
453                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
454                         // End of line (or of line buffer) met, colourise it\r
455                         lineBuffer[linePos] = '\0';\r
456                         ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywordlists, styler);\r
457                         linePos = 0;\r
458                         startLine = i + 1;\r
459                 }\r
460         }\r
461         if (linePos > 0) {      // Last line does not have ending characters\r
462                 lineBuffer[linePos] = '\0';\r
463                 ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1,\r
464                                    keywordlists, styler);\r
465         }\r
466 }\r
467 \r
468 static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) {\r
469         // It is needed to remember the current state to recognize starting\r
470         // comment lines before the first "diff " or "--- ". If a real\r
471         // difference starts then each line starting with ' ' is a whitespace\r
472         // otherwise it is considered a comment (Only in..., Binary file...)\r
473         if (0 == strncmp(lineBuffer, "diff ", 5)) {\r
474                 styler.ColourTo(endLine, SCE_DIFF_COMMAND);\r
475         } else if (0 == strncmp(lineBuffer, "Index: ", 7)) {  // For subversion's diff\r
476                 styler.ColourTo(endLine, SCE_DIFF_COMMAND);\r
477         } else if (0 == strncmp(lineBuffer, "---", 3)) {\r
478                 // In a context diff, --- appears in both the header and the position markers\r
479                 if (lineBuffer[3] == ' ' && atoi(lineBuffer + 4) && !strchr(lineBuffer, '/'))\r
480                         styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
481                 else if (lineBuffer[3] == '\r' || lineBuffer[3] == '\n')\r
482                         styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
483                 else\r
484                         styler.ColourTo(endLine, SCE_DIFF_HEADER);\r
485         } else if (0 == strncmp(lineBuffer, "+++ ", 4)) {\r
486                 // I don't know of any diff where "+++ " is a position marker, but for\r
487                 // consistency, do the same as with "--- " and "*** ".\r
488                 if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/'))\r
489                         styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
490                 else\r
491                         styler.ColourTo(endLine, SCE_DIFF_HEADER);\r
492         } else if (0 == strncmp(lineBuffer, "====", 4)) {  // For p4's diff\r
493                 styler.ColourTo(endLine, SCE_DIFF_HEADER);\r
494         } else if (0 == strncmp(lineBuffer, "***", 3)) {\r
495                 // In a context diff, *** appears in both the header and the position markers.\r
496                 // Also ******** is a chunk header, but here it's treated as part of the\r
497                 // position marker since there is no separate style for a chunk header.\r
498                 if (lineBuffer[3] == ' ' && atoi(lineBuffer+4) && !strchr(lineBuffer, '/'))\r
499                         styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
500                 else if (lineBuffer[3] == '*')\r
501                         styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
502                 else\r
503                         styler.ColourTo(endLine, SCE_DIFF_HEADER);\r
504         } else if (0 == strncmp(lineBuffer, "? ", 2)) {    // For difflib\r
505                 styler.ColourTo(endLine, SCE_DIFF_HEADER);\r
506         } else if (lineBuffer[0] == '@') {\r
507                 styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
508         } else if (lineBuffer[0] >= '0' && lineBuffer[0] <= '9') {\r
509                 styler.ColourTo(endLine, SCE_DIFF_POSITION);\r
510         } else if (lineBuffer[0] == '-' || lineBuffer[0] == '<') {\r
511                 styler.ColourTo(endLine, SCE_DIFF_DELETED);\r
512         } else if (lineBuffer[0] == '+' || lineBuffer[0] == '>') {\r
513                 styler.ColourTo(endLine, SCE_DIFF_ADDED);\r
514         } else if (lineBuffer[0] == '!') {\r
515                 styler.ColourTo(endLine, SCE_DIFF_CHANGED);\r
516         } else if (lineBuffer[0] != ' ') {\r
517                 styler.ColourTo(endLine, SCE_DIFF_COMMENT);\r
518         } else {\r
519                 styler.ColourTo(endLine, SCE_DIFF_DEFAULT);\r
520         }\r
521 }\r
522 \r
523 static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
524         char lineBuffer[1024];\r
525         styler.StartAt(startPos);\r
526         styler.StartSegment(startPos);\r
527         unsigned int linePos = 0;\r
528         for (unsigned int i = startPos; i < startPos + length; i++) {\r
529                 lineBuffer[linePos++] = styler[i];\r
530                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
531                         // End of line (or of line buffer) met, colourise it\r
532                         lineBuffer[linePos] = '\0';\r
533                         ColouriseDiffLine(lineBuffer, i, styler);\r
534                         linePos = 0;\r
535                 }\r
536         }\r
537         if (linePos > 0) {      // Last line does not have ending characters\r
538                 ColouriseDiffLine(lineBuffer, startPos + length - 1, styler);\r
539         }\r
540 }\r
541 \r
542 static void FoldDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
543         int curLine = styler.GetLine(startPos);\r
544         int curLineStart = styler.LineStart(curLine);\r
545         int prevLevel = curLine > 0 ? styler.LevelAt(curLine - 1) : SC_FOLDLEVELBASE;\r
546         int nextLevel;\r
547 \r
548         do {\r
549                 int lineType = styler.StyleAt(curLineStart);\r
550                 if (lineType == SCE_DIFF_COMMAND)\r
551                         nextLevel = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;\r
552                 else if (lineType == SCE_DIFF_HEADER)\r
553                         nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG;\r
554                 else if (lineType == SCE_DIFF_POSITION && styler[curLineStart] != '-')\r
555                         nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG;\r
556                 else if (prevLevel & SC_FOLDLEVELHEADERFLAG)\r
557                         nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1;\r
558                 else\r
559                         nextLevel = prevLevel;\r
560 \r
561                 if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel))\r
562                         styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG);\r
563 \r
564                 styler.SetLevel(curLine, nextLevel);\r
565                 prevLevel = nextLevel;\r
566 \r
567                 curLineStart = styler.LineStart(++curLine);\r
568         } while (static_cast<int>(startPos) + length > curLineStart);\r
569 }\r
570 \r
571 static void ColourisePoLine(\r
572     char *lineBuffer,\r
573     unsigned int lengthLine,\r
574     unsigned int startLine,\r
575     unsigned int endPos,\r
576     Accessor &styler) {\r
577 \r
578         unsigned int i = 0;\r
579         static unsigned int state = SCE_PO_DEFAULT;\r
580         unsigned int state_start = SCE_PO_DEFAULT;\r
581 \r
582         while ((i < lengthLine) && isspacechar(lineBuffer[i]))  // Skip initial spaces\r
583                 i++;\r
584         if (i < lengthLine) {\r
585                 if (lineBuffer[i] == '#') {\r
586                         // check if the comment contains any flags ("#, ") and\r
587                         // then whether the flags contain "fuzzy"\r
588                         if (strstart(lineBuffer, "#, ") && strstr(lineBuffer, "fuzzy"))\r
589                                 styler.ColourTo(endPos, SCE_PO_FUZZY);\r
590                         else\r
591                                 styler.ColourTo(endPos, SCE_PO_COMMENT);\r
592                 } else {\r
593                         if (lineBuffer[0] == '"') {\r
594                                 // line continuation, use previous style\r
595                                 styler.ColourTo(endPos, state);\r
596                                 return;\r
597                         // this implicitly also matches "msgid_plural"\r
598                         } else if (strstart(lineBuffer, "msgid")) {\r
599                                 state_start = SCE_PO_MSGID;\r
600                                 state = SCE_PO_MSGID_TEXT;\r
601                         } else if (strstart(lineBuffer, "msgstr")) {\r
602                                 state_start = SCE_PO_MSGSTR;\r
603                                 state = SCE_PO_MSGSTR_TEXT;\r
604                         } else if (strstart(lineBuffer, "msgctxt")) {\r
605                                 state_start = SCE_PO_MSGCTXT;\r
606                                 state = SCE_PO_MSGCTXT_TEXT;\r
607                         }\r
608                         if (state_start != SCE_PO_DEFAULT) {\r
609                                 // find the next space\r
610                                 while ((i < lengthLine) && ! isspacechar(lineBuffer[i]))\r
611                                         i++;\r
612                                 styler.ColourTo(startLine + i - 1, state_start);\r
613                                 styler.ColourTo(startLine + i, SCE_PO_DEFAULT);\r
614                                 styler.ColourTo(endPos, state);\r
615                         }\r
616                 }\r
617         } else {\r
618                 styler.ColourTo(endPos, SCE_PO_DEFAULT);\r
619         }\r
620 }\r
621 \r
622 static void ColourisePoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
623         char lineBuffer[1024];\r
624         styler.StartAt(startPos);\r
625         styler.StartSegment(startPos);\r
626         unsigned int linePos = 0;\r
627         unsigned int startLine = startPos;\r
628         for (unsigned int i = startPos; i < startPos + length; i++) {\r
629                 lineBuffer[linePos++] = styler[i];\r
630                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
631                         // End of line (or of line buffer) met, colourise it\r
632                         lineBuffer[linePos] = '\0';\r
633                         ColourisePoLine(lineBuffer, linePos, startLine, i, styler);\r
634                         linePos = 0;\r
635                         startLine = i + 1;\r
636                 }\r
637         }\r
638         if (linePos > 0) {      // Last line does not have ending characters\r
639                 ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);\r
640         }\r
641 }\r
642 \r
643 \r
644 static void ColourisePropsLine(\r
645     char *lineBuffer,\r
646     unsigned int lengthLine,\r
647     unsigned int startLine,\r
648     unsigned int endPos,\r
649     Accessor &styler) {\r
650 \r
651         unsigned int i = 0;\r
652         while ((i < lengthLine) && isspacechar(lineBuffer[i]))  // Skip initial spaces\r
653                 i++;\r
654         if (i < lengthLine) {\r
655                 if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') {\r
656                         styler.ColourTo(endPos, SCE_PROPS_COMMENT);\r
657                 } else if (lineBuffer[i] == '[') {\r
658                         styler.ColourTo(endPos, SCE_PROPS_SECTION);\r
659                 } else if (lineBuffer[i] == '@') {\r
660                         styler.ColourTo(startLine + i, SCE_PROPS_DEFVAL);\r
661                         if (lineBuffer[++i] == '=')\r
662                                 styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT);\r
663                         styler.ColourTo(endPos, SCE_PROPS_DEFAULT);\r
664                 } else {\r
665                         // Search for the '=' character\r
666                         while ((i < lengthLine) && (lineBuffer[i] != '='))\r
667                                 i++;\r
668                         if ((i < lengthLine) && (lineBuffer[i] == '=')) {\r
669                                 styler.ColourTo(startLine + i - 1, SCE_PROPS_KEY);\r
670                                 styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT);\r
671                                 styler.ColourTo(endPos, SCE_PROPS_DEFAULT);\r
672                         } else {\r
673                                 styler.ColourTo(endPos, SCE_PROPS_DEFAULT);\r
674                         }\r
675                 }\r
676         } else {\r
677                 styler.ColourTo(endPos, SCE_PROPS_DEFAULT);\r
678         }\r
679 }\r
680 \r
681 static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
682         char lineBuffer[1024];\r
683         styler.StartAt(startPos);\r
684         styler.StartSegment(startPos);\r
685         unsigned int linePos = 0;\r
686         unsigned int startLine = startPos;\r
687         for (unsigned int i = startPos; i < startPos + length; i++) {\r
688                 lineBuffer[linePos++] = styler[i];\r
689                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
690                         // End of line (or of line buffer) met, colourise it\r
691                         lineBuffer[linePos] = '\0';\r
692                         ColourisePropsLine(lineBuffer, linePos, startLine, i, styler);\r
693                         linePos = 0;\r
694                         startLine = i + 1;\r
695                 }\r
696         }\r
697         if (linePos > 0) {      // Last line does not have ending characters\r
698                 ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);\r
699         }\r
700 }\r
701 \r
702 // adaption by ksc, using the "} else {" trick of 1.53\r
703 // 030721\r
704 static void FoldPropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
705         bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;\r
706 \r
707         unsigned int endPos = startPos + length;\r
708         int visibleChars = 0;\r
709         int lineCurrent = styler.GetLine(startPos);\r
710 \r
711         char chNext = styler[startPos];\r
712         int styleNext = styler.StyleAt(startPos);\r
713         bool headerPoint = false;\r
714         int lev;\r
715 \r
716         for (unsigned int i = startPos; i < endPos; i++) {\r
717                 char ch = chNext;\r
718                 chNext = styler[i+1];\r
719 \r
720                 int style = styleNext;\r
721                 styleNext = styler.StyleAt(i + 1);\r
722                 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');\r
723 \r
724                 if (style == SCE_PROPS_SECTION) {\r
725                         headerPoint = true;\r
726                 }\r
727 \r
728                 if (atEOL) {\r
729                         lev = SC_FOLDLEVELBASE;\r
730 \r
731                         if (lineCurrent > 0) {\r
732                                 int levelPrevious = styler.LevelAt(lineCurrent - 1);\r
733 \r
734                                 if (levelPrevious & SC_FOLDLEVELHEADERFLAG) {\r
735                                         lev = SC_FOLDLEVELBASE + 1;\r
736                                 } else {\r
737                                         lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;\r
738                                 }\r
739                         }\r
740 \r
741                         if (headerPoint) {\r
742                                 lev = SC_FOLDLEVELBASE;\r
743                         }\r
744                         if (visibleChars == 0 && foldCompact)\r
745                                 lev |= SC_FOLDLEVELWHITEFLAG;\r
746 \r
747                         if (headerPoint) {\r
748                                 lev |= SC_FOLDLEVELHEADERFLAG;\r
749                         }\r
750                         if (lev != styler.LevelAt(lineCurrent)) {\r
751                                 styler.SetLevel(lineCurrent, lev);\r
752                         }\r
753 \r
754                         lineCurrent++;\r
755                         visibleChars = 0;\r
756                         headerPoint = false;\r
757                 }\r
758                 if (!isspacechar(ch))\r
759                         visibleChars++;\r
760         }\r
761 \r
762         if (lineCurrent > 0) {\r
763                 int levelPrevious = styler.LevelAt(lineCurrent - 1);\r
764                 if (levelPrevious & SC_FOLDLEVELHEADERFLAG) {\r
765                         lev = SC_FOLDLEVELBASE + 1;\r
766                 } else {\r
767                         lev = levelPrevious & SC_FOLDLEVELNUMBERMASK;\r
768                 }\r
769         } else {\r
770                 lev = SC_FOLDLEVELBASE;\r
771         }\r
772         int flagsNext = styler.LevelAt(lineCurrent);\r
773         styler.SetLevel(lineCurrent, lev | flagsNext & ~SC_FOLDLEVELNUMBERMASK);\r
774 }\r
775 \r
776 static void ColouriseMakeLine(\r
777     char *lineBuffer,\r
778     unsigned int lengthLine,\r
779     unsigned int startLine,\r
780     unsigned int endPos,\r
781     Accessor &styler) {\r
782 \r
783         unsigned int i = 0;\r
784         int lastNonSpace = -1;\r
785         unsigned int state = SCE_MAKE_DEFAULT;\r
786         bool bSpecial = false;\r
787 \r
788         // check for a tab character in column 0 indicating a command\r
789         bool bCommand = false;\r
790         if ((lengthLine > 0) && (lineBuffer[0] == '\t'))\r
791                 bCommand = true;\r
792 \r
793         // Skip initial spaces\r
794         while ((i < lengthLine) && isspacechar(lineBuffer[i])) {\r
795                 i++;\r
796         }\r
797         if (lineBuffer[i] == '#') {     // Comment\r
798                 styler.ColourTo(endPos, SCE_MAKE_COMMENT);\r
799                 return;\r
800         }\r
801         if (lineBuffer[i] == '!') {     // Special directive\r
802                 styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR);\r
803                 return;\r
804         }\r
805         while (i < lengthLine) {\r
806                 if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') {\r
807                         styler.ColourTo(startLine + i - 1, state);\r
808                         state = SCE_MAKE_IDENTIFIER;\r
809                 } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') {\r
810                         styler.ColourTo(startLine + i, state);\r
811                         state = SCE_MAKE_DEFAULT;\r
812                 }\r
813 \r
814                 // skip identifier and target styling if this is a command line\r
815                 if (!bSpecial && !bCommand) {\r
816                         if (lineBuffer[i] == ':') {\r
817                                 if (((i + 1) < lengthLine) && (lineBuffer[i + 1] == '=')) {\r
818                                         // it's a ':=', so style as an identifier\r
819                                         if (lastNonSpace >= 0)\r
820                                                 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);\r
821                                         styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);\r
822                                         styler.ColourTo(startLine + i + 1, SCE_MAKE_OPERATOR);\r
823                                 } else {\r
824                                         // We should check that no colouring was made since the beginning of the line,\r
825                                         // to avoid colouring stuff like /OUT:file\r
826                                         if (lastNonSpace >= 0)\r
827                                                 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);\r
828                                         styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);\r
829                                         styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);\r
830                                 }\r
831                                 bSpecial = true;        // Only react to the first ':' of the line\r
832                                 state = SCE_MAKE_DEFAULT;\r
833                         } else if (lineBuffer[i] == '=') {\r
834                                 if (lastNonSpace >= 0)\r
835                                         styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);\r
836                                 styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);\r
837                                 styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);\r
838                                 bSpecial = true;        // Only react to the first '=' of the line\r
839                                 state = SCE_MAKE_DEFAULT;\r
840                         }\r
841                 }\r
842                 if (!isspacechar(lineBuffer[i])) {\r
843                         lastNonSpace = i;\r
844                 }\r
845                 i++;\r
846         }\r
847         if (state == SCE_MAKE_IDENTIFIER) {\r
848                 styler.ColourTo(endPos, SCE_MAKE_IDEOL);        // Error, variable reference not ended\r
849         } else {\r
850                 styler.ColourTo(endPos, SCE_MAKE_DEFAULT);\r
851         }\r
852 }\r
853 \r
854 static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
855         char lineBuffer[1024];\r
856         styler.StartAt(startPos);\r
857         styler.StartSegment(startPos);\r
858         unsigned int linePos = 0;\r
859         unsigned int startLine = startPos;\r
860         for (unsigned int i = startPos; i < startPos + length; i++) {\r
861                 lineBuffer[linePos++] = styler[i];\r
862                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
863                         // End of line (or of line buffer) met, colourise it\r
864                         lineBuffer[linePos] = '\0';\r
865                         ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler);\r
866                         linePos = 0;\r
867                         startLine = i + 1;\r
868                 }\r
869         }\r
870         if (linePos > 0) {      // Last line does not have ending characters\r
871                 ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);\r
872         }\r
873 }\r
874 \r
875 static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine, int &startValue) {\r
876         if (lineBuffer[0] == '>') {\r
877                 // Command or return status\r
878                 return SCE_ERR_CMD;\r
879         } else if (lineBuffer[0] == '<') {\r
880                 // Diff removal, but not interested. Trapped to avoid hitting CTAG cases.\r
881                 return SCE_ERR_DEFAULT;\r
882         } else if (lineBuffer[0] == '!') {\r
883                 return SCE_ERR_DIFF_CHANGED;\r
884         } else if (lineBuffer[0] == '+') {\r
885                 if (strstart(lineBuffer, "+++ ")) {\r
886                         return SCE_ERR_DIFF_MESSAGE;\r
887                 } else {\r
888                         return SCE_ERR_DIFF_ADDITION;\r
889                 }\r
890         } else if (lineBuffer[0] == '-') {\r
891                 if (strstart(lineBuffer, "--- ")) {\r
892                         return SCE_ERR_DIFF_MESSAGE;\r
893                 } else {\r
894                         return SCE_ERR_DIFF_DELETION;\r
895                 }\r
896         } else if (strstart(lineBuffer, "cf90-")) {\r
897                 // Absoft Pro Fortran 90/95 v8.2 error and/or warning message\r
898                 return SCE_ERR_ABSF;\r
899         } else if (strstart(lineBuffer, "fortcom:")) {\r
900                 // Intel Fortran Compiler v8.0 error/warning message\r
901                 return SCE_ERR_IFORT;\r
902         } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) {\r
903                 return SCE_ERR_PYTHON;\r
904         } else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) {\r
905                 return SCE_ERR_PHP;\r
906         } else if ((strstart(lineBuffer, "Error ") ||\r
907                     strstart(lineBuffer, "Warning ")) &&\r
908                    strstr(lineBuffer, " at (") &&\r
909                    strstr(lineBuffer, ") : ") &&\r
910                    (strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) {\r
911                 // Intel Fortran Compiler error/warning message\r
912                 return SCE_ERR_IFC;\r
913         } else if (strstart(lineBuffer, "Error ")) {\r
914                 // Borland error message\r
915                 return SCE_ERR_BORLAND;\r
916         } else if (strstart(lineBuffer, "Warning ")) {\r
917                 // Borland warning message\r
918                 return SCE_ERR_BORLAND;\r
919         } else if (strstr(lineBuffer, "at line " ) &&\r
920                    (strstr(lineBuffer, "at line " ) < (lineBuffer + lengthLine)) &&\r
921                    strstr(lineBuffer, "file ") &&\r
922                    (strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) {\r
923                 // Lua 4 error message\r
924                 return SCE_ERR_LUA;\r
925         } else if (strstr(lineBuffer, " at " ) &&\r
926                    (strstr(lineBuffer, " at " ) < (lineBuffer + lengthLine)) &&\r
927                    strstr(lineBuffer, " line ") &&\r
928                    (strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) &&\r
929                    (strstr(lineBuffer, " at " ) < (strstr(lineBuffer, " line ")))) {\r
930                 // perl error message\r
931                 return SCE_ERR_PERL;\r
932         } else if ((memcmp(lineBuffer, "   at ", 6) == 0) &&\r
933                    strstr(lineBuffer, ":line ")) {\r
934                 // A .NET traceback\r
935                 return SCE_ERR_NET;\r
936         } else if (strstart(lineBuffer, "Line ") &&\r
937                    strstr(lineBuffer, ", file ")) {\r
938                 // Essential Lahey Fortran error message\r
939                 return SCE_ERR_ELF;\r
940         } else if (strstart(lineBuffer, "line ") &&\r
941                    strstr(lineBuffer, " column ")) {\r
942                 // HTML tidy style: line 42 column 1\r
943                 return SCE_ERR_TIDY;\r
944         } else if (strstart(lineBuffer, "\tat ") &&\r
945                    strstr(lineBuffer, "(") &&\r
946                    strstr(lineBuffer, ".java:")) {\r
947                 // Java stack back trace\r
948                 return SCE_ERR_JAVA_STACK;\r
949         } else {\r
950                 // Look for one of the following formats:\r
951                 // GCC: <filename>:<line>:<message>\r
952                 // Microsoft: <filename>(<line>) :<message>\r
953                 // Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal\r
954                 // Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal\r
955                 // Microsoft: <filename>(<line>,<column>)<message>\r
956                 // CTags: \t<message>\r
957                 // Lua 5 traceback: \t<filename>:<line>:<message>\r
958                 // Lua 5.1: <exe>: <filename>:<line>:<message>\r
959                 bool initialTab = (lineBuffer[0] == '\t');\r
960                 bool initialColonPart = false;\r
961                 enum { stInitial,\r
962                         stGccStart, stGccDigit, stGcc,\r
963                         stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet,\r
964                         stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags,\r
965                         stUnrecognized\r
966                 } state = stInitial;\r
967                 for (unsigned int i = 0; i < lengthLine; i++) {\r
968                         char ch = lineBuffer[i];\r
969                         char chNext = ' ';\r
970                         if ((i + 1) < lengthLine)\r
971                                 chNext = lineBuffer[i + 1];\r
972                         if (state == stInitial) {\r
973                                 if (ch == ':') {\r
974                                         // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)\r
975                                         if ((chNext != '\\') && (chNext != '/') && (chNext != ' ')) {\r
976                                                 // This check is not completely accurate as may be on\r
977                                                 // GTK+ with a file name that includes ':'.\r
978                                                 state = stGccStart;\r
979                                         } else if (chNext == ' ') { // indicates a Lua 5.1 error message\r
980                                                 initialColonPart = true;\r
981                                         }\r
982                                 } else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) {\r
983                                         // May be Microsoft\r
984                                         // Check against '0' often removes phone numbers\r
985                                         state = stMsStart;\r
986                                 } else if ((ch == '\t') && (!initialTab)) {\r
987                                         // May be CTags\r
988                                         state = stCtagsStart;\r
989                                 }\r
990                         } else if (state == stGccStart) {       // <filename>:\r
991                                 state = Is1To9(ch) ? stGccDigit : stUnrecognized;\r
992                         } else if (state == stGccDigit) {       // <filename>:<line>\r
993                                 if (ch == ':') {\r
994                                         state = stGcc;  // :9.*: is GCC\r
995                                         startValue = i + 1;\r
996                                         break;\r
997                                 } else if (!Is0To9(ch)) {\r
998                                         state = stUnrecognized;\r
999                                 }\r
1000                         } else if (state == stMsStart) {        // <filename>(\r
1001                                 state = Is0To9(ch) ? stMsDigit : stUnrecognized;\r
1002                         } else if (state == stMsDigit) {        // <filename>(<line>\r
1003                                 if (ch == ',') {\r
1004                                         state = stMsDigitComma;\r
1005                                 } else if (ch == ')') {\r
1006                                         state = stMsBracket;\r
1007                                 } else if ((ch != ' ') && !Is0To9(ch)) {\r
1008                                         state = stUnrecognized;\r
1009                                 }\r
1010                         } else if (state == stMsBracket) {      // <filename>(<line>)\r
1011                                 if ((ch == ' ') && (chNext == ':')) {\r
1012                                         state = stMsVc;\r
1013                                 } else if ((ch == ':' && chNext == ' ') || (ch == ' ')) {\r
1014                                         // Possibly Delphi.. don't test against chNext as it's one of the strings below.\r
1015                                         char word[512];\r
1016                                         unsigned int j, chPos;\r
1017                                         unsigned numstep;\r
1018                                         chPos = 0;\r
1019                                         if (ch == ' ')\r
1020                                                 numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.\r
1021                                         else\r
1022                                                 numstep = 2; // otherwise add 2.\r
1023                                         for (j = i + numstep; j < lengthLine && isalpha(lineBuffer[j]) && chPos < sizeof(word) - 1; j++)\r
1024                                                 word[chPos++] = lineBuffer[j];\r
1025                                         word[chPos] = 0;\r
1026                                         if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") ||\r
1027                                                 !CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") ||\r
1028                                                 !CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) {\r
1029                                                 state = stMsVc;\r
1030                                         } else\r
1031                                                 state = stUnrecognized;\r
1032                                 } else {\r
1033                                         state = stUnrecognized;\r
1034                                 }\r
1035                         } else if (state == stMsDigitComma) {   // <filename>(<line>,\r
1036                                 if (ch == ')') {\r
1037                                         state = stMsDotNet;\r
1038                                         break;\r
1039                                 } else if ((ch != ' ') && !Is0To9(ch)) {\r
1040                                         state = stUnrecognized;\r
1041                                 }\r
1042                         } else if (state == stCtagsStart) {\r
1043                                 if ((lineBuffer[i - 1] == '\t') &&\r
1044                                         ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) {\r
1045                                         state = stCtags;\r
1046                                         break;\r
1047                                 } else if ((ch == '/') && (lineBuffer[i + 1] == '^')) {\r
1048                                         state = stCtagsStartString;\r
1049                                 }\r
1050                         } else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) {\r
1051                                 state = stCtagsStringDollar;\r
1052                                 break;\r
1053                         }\r
1054                 }\r
1055                 if (state == stGcc) {\r
1056                         return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC;\r
1057                 } else if ((state == stMsVc) || (state == stMsDotNet)) {\r
1058                         return SCE_ERR_MS;\r
1059                 } else if ((state == stCtagsStringDollar) || (state == stCtags)) {\r
1060                         return SCE_ERR_CTAG;\r
1061                 } else {\r
1062                         return SCE_ERR_DEFAULT;\r
1063                 }\r
1064         }\r
1065 }\r
1066 \r
1067 static void ColouriseErrorListLine(\r
1068     char *lineBuffer,\r
1069     unsigned int lengthLine,\r
1070     unsigned int endPos,\r
1071     Accessor &styler,\r
1072         bool valueSeparate) {\r
1073         int startValue = -1;\r
1074         int style = RecogniseErrorListLine(lineBuffer, lengthLine, startValue);\r
1075         if (valueSeparate && (startValue >= 0)) {\r
1076                 styler.ColourTo(endPos - (lengthLine - startValue), style);\r
1077                 styler.ColourTo(endPos, SCE_ERR_VALUE);\r
1078         } else {\r
1079                 styler.ColourTo(endPos, style);\r
1080         }\r
1081 }\r
1082 \r
1083 static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {\r
1084         char lineBuffer[10000];\r
1085         styler.StartAt(startPos);\r
1086         styler.StartSegment(startPos);\r
1087         unsigned int linePos = 0;\r
1088         bool valueSeparate = styler.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;\r
1089         for (unsigned int i = startPos; i < startPos + length; i++) {\r
1090                 lineBuffer[linePos++] = styler[i];\r
1091                 if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
1092                         // End of line (or of line buffer) met, colourise it\r
1093                         lineBuffer[linePos] = '\0';\r
1094                         ColouriseErrorListLine(lineBuffer, linePos, i, styler, valueSeparate);\r
1095                         linePos = 0;\r
1096                 }\r
1097         }\r
1098         if (linePos > 0) {      // Last line does not have ending characters\r
1099                 ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler, valueSeparate);\r
1100         }\r
1101 }\r
1102 \r
1103 static int isSpecial(char s) {\r
1104         return (s == '\\') || (s == ',') || (s == ';') || (s == '\'') || (s == ' ') ||\r
1105                (s == '\"') || (s == '`') || (s == '^') || (s == '~');\r
1106 }\r
1107 \r
1108 static int isTag(int start, Accessor &styler) {\r
1109         char s[6];\r
1110         unsigned int i = 0, e = 1;\r
1111         while (i < 5 && e) {\r
1112                 s[i] = styler[start + i];\r
1113                 i++;\r
1114                 e = styler[start + i] != '{';\r
1115         }\r
1116         s[i] = '\0';\r
1117         return (strcmp(s, "begin") == 0) || (strcmp(s, "end") == 0);\r
1118 }\r
1119 \r
1120 static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle,\r
1121                               WordList *[], Accessor &styler) {\r
1122 \r
1123         styler.StartAt(startPos);\r
1124 \r
1125         int state = initStyle;\r
1126         char chNext = styler[startPos];\r
1127         styler.StartSegment(startPos);\r
1128         int lengthDoc = startPos + length;\r
1129 \r
1130         for (int i = startPos; i < lengthDoc; i++) {\r
1131                 char ch = chNext;\r
1132                 chNext = styler.SafeGetCharAt(i + 1);\r
1133 \r
1134                 if (styler.IsLeadByte(ch)) {\r
1135                         chNext = styler.SafeGetCharAt(i + 2);\r
1136                         i++;\r
1137                         continue;\r
1138                 }\r
1139                 switch (state) {\r
1140                 case SCE_L_DEFAULT :\r
1141                         switch (ch) {\r
1142                         case '\\' :\r
1143                                 styler.ColourTo(i - 1, state);\r
1144                                 if (isSpecial(styler[i + 1])) {\r
1145                                         styler.ColourTo(i + 1, SCE_L_COMMAND);\r
1146                                         i++;\r
1147                                         chNext = styler.SafeGetCharAt(i + 1);\r
1148                                 } else {\r
1149                                         if (isTag(i + 1, styler))\r
1150                                                 state = SCE_L_TAG;\r
1151                                         else\r
1152                                                 state = SCE_L_COMMAND;\r
1153                                 }\r
1154                                 break;\r
1155                         case '$' :\r
1156                                 styler.ColourTo(i - 1, state);\r
1157                                 state = SCE_L_MATH;\r
1158                                 if (chNext == '$') {\r
1159                                         i++;\r
1160                                         chNext = styler.SafeGetCharAt(i + 1);\r
1161                                 }\r
1162                                 break;\r
1163                         case '%' :\r
1164                                 styler.ColourTo(i - 1, state);\r
1165                                 state = SCE_L_COMMENT;\r
1166                                 break;\r
1167                         }\r
1168                         break;\r
1169                 case SCE_L_COMMAND :\r
1170                         if (chNext == '[' || chNext == '{' || chNext == '}' ||\r
1171                                 chNext == ' ' || chNext == '\r' || chNext == '\n') {\r
1172                                 styler.ColourTo(i, state);\r
1173                                 state = SCE_L_DEFAULT;\r
1174                                 i++;\r
1175                                 chNext = styler.SafeGetCharAt(i + 1);\r
1176                         }\r
1177                         break;\r
1178                 case SCE_L_TAG :\r
1179                         if (ch == '}') {\r
1180                                 styler.ColourTo(i, state);\r
1181                                 state = SCE_L_DEFAULT;\r
1182                         }\r
1183                         break;\r
1184                 case SCE_L_MATH :\r
1185                         if (ch == '$') {\r
1186                                 if (chNext == '$') {\r
1187                                         i++;\r
1188                                         chNext = styler.SafeGetCharAt(i + 1);\r
1189                                 }\r
1190                                 styler.ColourTo(i, state);\r
1191                                 state = SCE_L_DEFAULT;\r
1192                         }\r
1193                         break;\r
1194                 case SCE_L_COMMENT :\r
1195                         if (ch == '\r' || ch == '\n') {\r
1196                                 styler.ColourTo(i - 1, state);\r
1197                                 state = SCE_L_DEFAULT;\r
1198                         }\r
1199                 }\r
1200         }\r
1201         styler.ColourTo(lengthDoc-1, state);\r
1202 }\r
1203 \r
1204 static const char * const batchWordListDesc[] = {\r
1205         "Internal Commands",\r
1206         "External Commands",\r
1207         0\r
1208 };\r
1209 \r
1210 static const char * const emptyWordListDesc[] = {\r
1211         0\r
1212 };\r
1213 \r
1214 static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[],\r
1215                             Accessor &styler) {\r
1216         // Null language means all style bytes are 0 so just mark the end - no need to fill in.\r
1217         if (length > 0) {\r
1218                 styler.StartAt(startPos + length - 1);\r
1219                 styler.StartSegment(startPos + length - 1);\r
1220                 styler.ColourTo(startPos + length - 1, 0);\r
1221         }\r
1222 }\r
1223 \r
1224 LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc);\r
1225 LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc);\r
1226 LexerModule lmPo(SCLEX_PO, ColourisePoDoc, "po", 0, emptyWordListDesc);\r
1227 LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc);\r
1228 LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc);\r
1229 LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc);\r
1230 LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex", 0, emptyWordListDesc);\r
1231 LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null");\r