OSDN Git Service

Merge pull request #5 from WinMerge/master
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / parsers / html.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:    html.cpp
3 //  Version: 1.1.0.4
4 //  Updated: 19-Jul-1998
5 //
6 //  Copyright:  Ferdinand Prantl, portions by Stcherbatchenko Andrei
7 //  E-mail:     prantl@ff.cuni.cz
8 //
9 //  HTML syntax highlighing definition
10 //
11 //  You are free to use or modify this code to the following restrictions:
12 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
13 //  will be enough. If you can't (or don't want to), contact me personally.
14 //  - LEAVE THIS HEADER INTACT
15 ////////////////////////////////////////////////////////////////////////////
16
17 #include "StdAfx.h"
18 #include "crystallineparser.h"
19 #include "../SyntaxColors.h"
20 #include "../utils/string_util.h"
21
22 #ifdef _DEBUG
23 #define new DEBUG_NEW
24 #endif
25
26 DWORD
27 CrystalLineParser::ParseLineHtml (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
28 {
29   if (nLength == 0)
30     return dwCookie & (COOKIE_EXT_COMMENT|COOKIE_EXT_USER1);
31
32   bool bFirstChar = (dwCookie & ~(COOKIE_EXT_COMMENT|COOKIE_EXT_USER1)) == 0;
33   bool bRedefineBlock = true;
34   bool bDecIndex = false;
35   int nIdentBegin = -1;
36   int nPrevI = -1;
37   int I=0;
38   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
39     {
40       if (I == nPrevI)
41         {
42           // CharNext did not advance, so we're at the end of the string
43           // and we already handled this character, so stop
44           break;
45         }
46
47       if (bRedefineBlock)
48         {
49           int nPos = I;
50           if (bDecIndex)
51             nPos = nPrevI;
52           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
53             {
54               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
55             }
56           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
57             {
58               DEFINE_BLOCK (nPos, COLORINDEX_STRING);
59             }
60           else if (dwCookie & COOKIE_PREPROCESSOR)
61             {
62               DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
63             }
64           else if (dwCookie & COOKIE_EXT_USER1)
65             {
66               DEFINE_BLOCK (nPos, COLORINDEX_FUNCNAME);
67             }
68           else
69             {
70               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.')
71                 {
72                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
73                 }
74               else
75                 {
76                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
77                   bRedefineBlock = true;
78                   bDecIndex = true;
79                   goto out;
80                 }
81             }
82           bRedefineBlock = false;
83           bDecIndex = false;
84         }
85 out:
86
87       // Can be bigger than length if there is binary data
88       // See bug #1474782 Crash when comparing SQL with with binary data
89       if (I >= nLength || pszChars[I] == 0)
90         break;
91
92       if (dwCookie & COOKIE_COMMENT)
93         {
94           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
95           dwCookie |= COOKIE_COMMENT;
96           break;
97         }
98
99       //  String constant "...."
100       if (dwCookie & COOKIE_STRING)
101         {
102           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
103             {
104               dwCookie &= ~COOKIE_STRING;
105               bRedefineBlock = true;
106             }
107           continue;
108         }
109
110       //  Char constant '..'
111       if (dwCookie & COOKIE_CHAR)
112         {
113           if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
114             {
115               dwCookie &= ~COOKIE_CHAR;
116               bRedefineBlock = true;
117             }
118           continue;
119         }
120
121       //  Extended comment <!--....-->
122       if (dwCookie & COOKIE_EXT_COMMENT)
123         {
124           if (I > 1 && pszChars[I] == '>' && pszChars[nPrevI] == '-' && *::CharPrev(pszChars, pszChars + nPrevI) == '-')
125             {
126               dwCookie &= ~COOKIE_EXT_COMMENT;
127               bRedefineBlock = true;
128             }
129           continue;
130         }
131
132       //  Extended comment <?....?>
133       if (dwCookie & COOKIE_EXT_USER1)
134         {
135           if (I > 0 && pszChars[I] == '>' && (pszChars[nPrevI] == '?' || pszChars[nPrevI] == '%'))
136             {
137               dwCookie &= ~COOKIE_EXT_USER1;
138               bRedefineBlock = true;
139             }
140           continue;
141         }
142
143       //  Normal text
144       if ((dwCookie & COOKIE_PREPROCESSOR) && pszChars[I] == '"')
145         {
146           DEFINE_BLOCK (I, COLORINDEX_STRING);
147           dwCookie |= COOKIE_STRING;
148           continue;
149         }
150
151       if ((dwCookie & COOKIE_PREPROCESSOR) && pszChars[I] == '\'')
152         {
153           // if (I + 1 < nLength && pszChars[I + 1] == '\'' || I + 2 < nLength && pszChars[I + 1] != '\\' && pszChars[I + 2] == '\'' || I + 3 < nLength && pszChars[I + 1] == '\\' && pszChars[I + 3] == '\'')
154           if (!I || !xisalnum (pszChars[nPrevI]))
155             {
156               DEFINE_BLOCK (I, COLORINDEX_STRING);
157               dwCookie |= COOKIE_CHAR;
158               continue;
159             }
160         }
161
162       if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength - 3 && pszChars[I] == '<' && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')
163         {
164           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
165           I += 3;
166           dwCookie |= COOKIE_EXT_COMMENT;
167           dwCookie &= ~COOKIE_PREPROCESSOR;
168           continue;
169         }
170
171       if (bFirstChar)
172         {
173           if (!xisspace (pszChars[I]))
174             bFirstChar = false;
175         }
176
177       if (pBuf == nullptr)
178         continue;               //  We don't need to extract keywords,
179       //  for faster parsing skip the rest of loop
180
181       if (xisalnum (pszChars[I]) || pszChars[I] == '.')
182         {
183           if (nIdentBegin == -1)
184             nIdentBegin = I;
185         }
186       else
187         {
188           if (nIdentBegin >= 0)
189             {
190               if (dwCookie & COOKIE_PREPROCESSOR)
191                 {
192                   if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
193                     {
194                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
195                     }
196                   else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
197                     {
198                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
199                     }
200                   else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
201                     {
202                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
203                     }
204                   else
205                     {
206                       goto next;
207                     }
208                 }
209               else if (dwCookie & COOKIE_USER1)
210                 {
211                   if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
212                     {
213                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
214                     }
215                   else
216                     {
217                       goto next;
218                     }
219                 }
220               bRedefineBlock = true;
221               bDecIndex = true;
222               nIdentBegin = -1;
223 next:
224               ;
225             }
226
227           //  User1 start: <?
228           if (I < nLength && pszChars[I] == '<' && I < nLength - 1 && (pszChars[I + 1] == '?' || pszChars[I + 1] == '%'))
229             {
230               DEFINE_BLOCK (I, COLORINDEX_FUNCNAME);
231               dwCookie |= COOKIE_EXT_USER1;
232               nIdentBegin = -1;
233               continue;
234             }
235
236           //  Preprocessor start: < or bracket
237           if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength && (pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')/* || pszChars[I] == '{'*/))
238             {
239               DEFINE_BLOCK (I, COLORINDEX_OPERATOR);
240               DEFINE_BLOCK (I + 1, COLORINDEX_PREPROCESSOR);
241               dwCookie |= COOKIE_PREPROCESSOR;
242               nIdentBegin = -1;
243               continue;
244             }
245
246           //  User1 end: ?>
247           if (dwCookie & COOKIE_EXT_USER1)
248             {
249               if (I > 0 && pszChars[I] == '>' && (pszChars[nPrevI] == '?' || pszChars[nPrevI] == '%'))
250                 {
251                   dwCookie &= ~COOKIE_EXT_USER1;
252                   nIdentBegin = -1;
253                   bRedefineBlock = true;
254                   bDecIndex = true;
255                   continue;
256                 }
257             }
258
259           //  Preprocessor end: > or bracket
260           if (dwCookie & COOKIE_PREPROCESSOR)
261             {
262               if (pszChars[I] == '>'/* || pszChars[I] == '}'*/)
263                 {
264                   dwCookie &= ~COOKIE_PREPROCESSOR;
265                   nIdentBegin = -1;
266                   bRedefineBlock = true;
267                   bDecIndex = true;
268                   continue;
269                 }
270             }
271
272           //  Preprocessor start: &
273           if (pszChars[I] == '&')
274             {
275               dwCookie |= COOKIE_USER1;
276               nIdentBegin = -1;
277               continue;
278             }
279
280           //  Preprocessor end: ;
281           if (dwCookie & COOKIE_USER1)
282             {
283               if (pszChars[I] == ';')
284                 {
285                   dwCookie &= ~COOKIE_USER1;
286                   nIdentBegin = -1;
287                   continue;
288                 }
289             }
290         }
291     }
292
293   if (nIdentBegin >= 0 && (dwCookie & COOKIE_PREPROCESSOR))
294     {
295       if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
296         {
297           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
298         }
299       else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
300         {
301           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
302         }
303       else if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
304         {
305           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
306         }
307       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
308         {
309           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
310         }
311       else
312         {
313           bool bFunction = false;
314
315           for (int j = I; j < nLength; j++)
316             {
317               if (!xisspace (pszChars[j]))
318                 {
319                   if (pszChars[j] == '(')
320                     {
321                       bFunction = true;
322                     }
323                   break;
324                 }
325             }
326           if (bFunction)
327             {
328               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
329             }
330         }
331     }
332
333   //  User1 start: <?
334   if (I < nLength && pszChars[I] == '<' && I < nLength - 1 && (pszChars[I + 1] == '?' || pszChars[I + 1] == '%'))
335     {
336       DEFINE_BLOCK (I, COLORINDEX_FUNCNAME);
337       dwCookie |= COOKIE_EXT_USER1;
338       nIdentBegin = -1;
339       goto end;
340     }
341
342   //  Preprocessor start: < or {
343   if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength && (pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')/* || pszChars[I] == '{'*/))
344     {
345       DEFINE_BLOCK (I, COLORINDEX_OPERATOR);
346       DEFINE_BLOCK (I + 1, COLORINDEX_PREPROCESSOR);
347       dwCookie |= COOKIE_PREPROCESSOR;
348       nIdentBegin = -1;
349       goto end;
350     }
351
352   //  User1 end: ?>
353   if (dwCookie & COOKIE_EXT_USER1)
354     {
355       if (I > 0 && pszChars[I] == '>' && (pszChars[nPrevI] == '?' || pszChars[nPrevI] == '%'))
356         {
357           dwCookie &= ~COOKIE_EXT_USER1;
358           nIdentBegin = -1;
359         }
360     }
361
362   //  Preprocessor end: > or }
363   if (dwCookie & COOKIE_PREPROCESSOR)
364     {
365       if (pszChars[I] == '>'/* || pszChars[I] == '}'*/)
366         {
367           dwCookie &= ~COOKIE_PREPROCESSOR;
368           nIdentBegin = -1;
369         }
370     }
371
372 end:
373   dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_PREPROCESSOR | COOKIE_EXT_USER1);
374   return dwCookie;
375 }