1 ///////////////////////////////////////////////////////////////////////////
4 // Updated: 19-Jul-1998
6 // Copyright: Ferdinand Prantl, portions by Stcherbatchenko Andrei
7 // E-mail: prantl@ff.cuni.cz
9 // HTML syntax highlighing definition
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 ////////////////////////////////////////////////////////////////////////////
18 #include "crystallineparser.h"
19 #include "../SyntaxColors.h"
20 #include "../utils/string_util.h"
26 static void AdjustCharPosInTextBlocks(CrystalLineParser::TEXTBLOCK* pBuf, int startBlock, int endBlock, int offset)
28 for (int i = startBlock; i <= endBlock; ++i)
29 pBuf[i].m_nCharPos += offset;
33 CrystalLineParser::ParseLineHtmlEx (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems, int nEmbeddedLanguage)
36 return dwCookie & (COOKIE_EXT_COMMENT|COOKIE_EXT_USER1|COOKIE_ELEMENT|COOKIE_BLOCK_SCRIPT|COOKIE_BLOCK_STYLE|COOKIE_EXT_DEFINITION|COOKIE_EXT_VALUE);
38 bool bRedefineBlock = true;
39 if (!(dwCookie & COOKIE_ELEMENT))
40 bRedefineBlock = !(dwCookie & (COOKIE_EXT_USER1|COOKIE_BLOCK_SCRIPT|COOKIE_BLOCK_STYLE));
41 bool bDecIndex = false;
45 for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
49 // CharNext did not advance, so we're at the end of the string
50 // and we already handled this character, so stop
59 if (dwCookie & COOKIE_EXT_COMMENT)
61 DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
63 else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
65 DEFINE_BLOCK (nPos, COLORINDEX_STRING);
67 else if (dwCookie & COOKIE_ELEMENT)
69 DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
73 if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.')
75 DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
79 DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
80 bRedefineBlock = true;
85 bRedefineBlock = false;
90 // Can be bigger than length if there is binary data
91 // See bug #1474782 Crash when comparing SQL with with binary data
92 if (I >= nLength || pszChars[I] == 0)
95 if (!(dwCookie & COOKIE_ELEMENT) && (dwCookie & (COOKIE_EXT_USER1|COOKIE_BLOCK_SCRIPT|COOKIE_BLOCK_STYLE)))
97 if (dwCookie & COOKIE_BLOCK_SCRIPT)
99 const TCHAR *pszEnd = _tcsstr(pszChars + I, _T("</script>"));
100 int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
101 int nActualItemsEmbedded = 0;
102 dwCookie = ParseLineJavaScript(dwCookie & ~COOKIE_BLOCK_SCRIPT, pszChars + I, nextI - I, pBuf + nActualItems, nActualItemsEmbedded);
103 AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, I);
104 nActualItems += nActualItemsEmbedded;
106 dwCookie |= COOKIE_BLOCK_SCRIPT;
110 bRedefineBlock = true;
114 else if (dwCookie & COOKIE_BLOCK_STYLE)
116 const TCHAR *pszEnd = _tcsstr(pszChars + I, _T("</style>"));
117 int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
118 int nActualItemsEmbedded = 0;
119 dwCookie = ParseLineCss(dwCookie & ~COOKIE_BLOCK_STYLE, pszChars + I, nextI - I, pBuf + nActualItems, nActualItemsEmbedded);
120 AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, I);
121 nActualItems += nActualItemsEmbedded;
123 dwCookie |= COOKIE_BLOCK_STYLE;
127 bRedefineBlock = true;
131 else if ((dwCookie & COOKIE_EXT_USER1))
133 const TCHAR *pszEnd = _tcsstr(pszChars + I, _T("?>"));
135 pszEnd = _tcsstr(pszChars + I, _T("%>"));
136 int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
137 unsigned (*pParseLineFunc)(unsigned, const TCHAR *, int, TEXTBLOCK *, int &);
138 switch (nEmbeddedLanguage)
140 case SRC_BASIC: pParseLineFunc = ParseLineBasic; break;
141 case SRC_PHP: pParseLineFunc = ParseLinePhpLanguage; break;
142 default: pParseLineFunc = ParseLineJavaScript; break;
144 int nActualItemsEmbedded = 0;
145 dwCookie = pParseLineFunc(dwCookie & ~COOKIE_EXT_USER1, pszChars + I, nextI - I, pBuf + nActualItems, nActualItemsEmbedded);
146 AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, I);
147 nActualItems += nActualItemsEmbedded;
149 dwCookie |= COOKIE_EXT_USER1;
153 bRedefineBlock = true;
160 // String constant "...."
161 if (dwCookie & COOKIE_STRING)
163 if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
165 dwCookie &= ~COOKIE_STRING;
166 bRedefineBlock = true;
171 // Char constant '..'
172 if (dwCookie & COOKIE_CHAR)
174 if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
176 dwCookie &= ~COOKIE_CHAR;
177 bRedefineBlock = true;
182 // Extended comment <!--....-->
183 if (dwCookie & COOKIE_EXT_COMMENT)
185 if (I > 1 && pszChars[I] == '>' && pszChars[nPrevI] == '-' && *::CharPrev(pszChars, pszChars + nPrevI) == '-')
187 dwCookie &= ~COOKIE_EXT_COMMENT;
188 bRedefineBlock = true;
194 if ((dwCookie & COOKIE_ELEMENT) && pszChars[I] == '"')
196 DEFINE_BLOCK (I, COLORINDEX_STRING);
197 dwCookie |= COOKIE_STRING;
201 if ((dwCookie & COOKIE_ELEMENT) && pszChars[I] == '\'')
203 // 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] == '\'')
204 if (!I || !xisalnum (pszChars[nPrevI]))
206 DEFINE_BLOCK (I, COLORINDEX_STRING);
207 dwCookie |= COOKIE_CHAR;
212 if (I < nLength - 3 && pszChars[I] == '<' && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')
214 DEFINE_BLOCK (I, COLORINDEX_COMMENT);
216 dwCookie |= COOKIE_EXT_COMMENT;
217 dwCookie &= ~COOKIE_ELEMENT;
222 if (I < nLength && pszChars[I] == '<' && I < nLength - 1 && (pszChars[I + 1] == '?' || pszChars[I + 1] == '%'))
224 DEFINE_BLOCK (I, COLORINDEX_NORMALTEXT);
225 dwCookie |= COOKIE_EXT_USER1;
231 continue; // We don't need to extract keywords,
232 // for faster parsing skip the rest of loop
234 if (xisalnum (pszChars[I]) || pszChars[I] == '.')
236 if (nIdentBegin == -1)
241 if (nIdentBegin >= 0)
243 if (dwCookie & COOKIE_ELEMENT)
245 if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
247 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
248 if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
249 dwCookie |= COOKIE_BLOCK_SCRIPT;
250 else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
251 dwCookie |= COOKIE_BLOCK_STYLE;
253 else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
255 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
257 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
259 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
266 else if (dwCookie & COOKIE_USER1)
268 if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
270 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
277 bRedefineBlock = true;
284 // Preprocessor start: < or bracket
285 if (I < nLength && pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-'))
287 DEFINE_BLOCK (I, COLORINDEX_OPERATOR);
288 DEFINE_BLOCK (I + 1, COLORINDEX_PREPROCESSOR);
289 dwCookie |= COOKIE_ELEMENT;
294 // Preprocessor end: > or bracket
295 if (dwCookie & COOKIE_ELEMENT)
297 if (pszChars[I] == '>')
299 dwCookie &= ~COOKIE_ELEMENT;
301 bRedefineBlock = true;
307 // Preprocessor start: &
308 if (pszChars[I] == '&')
310 dwCookie |= COOKIE_USER1;
315 // Preprocessor end: ;
316 if (dwCookie & COOKIE_USER1)
318 if (pszChars[I] == ';')
320 dwCookie &= ~COOKIE_USER1;
328 if (nIdentBegin >= 0 && (dwCookie & COOKIE_ELEMENT))
330 if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
332 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
333 if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
334 dwCookie |= COOKIE_BLOCK_SCRIPT;
335 else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
336 dwCookie |= COOKIE_BLOCK_STYLE;
338 else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
340 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
342 else if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
344 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
346 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
348 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
352 dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_ELEMENT | COOKIE_EXT_USER1 | COOKIE_BLOCK_SCRIPT | COOKIE_BLOCK_STYLE | COOKIE_EXT_DEFINITION | COOKIE_EXT_VALUE);
357 CrystalLineParser::ParseLineHtml (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
359 return ParseLineHtmlEx(dwCookie, pszChars, nLength, pBuf, nActualItems, SRC_JAVA);