1 ///////////////////////////////////////////////////////////////////////////
4 // Updated: 19-Jul-1998
6 // Copyright: Ferdinand Prantl, portions by Stcherbatchenko Andrei
7 // E-mail: prantl@ff.cuni.cz
9 // PHP 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 LPCTSTR s_apszPhpKeywordList[] =
65 _T ("php_user_filter"),
78 static LPCTSTR s_apszPhp1KeywordList[] =
85 static LPCTSTR s_apszPhp2KeywordList[] =
95 IsPhpKeyword (LPCTSTR pszChars, int nLength)
97 return ISXKEYWORDI (s_apszPhpKeywordList, pszChars, nLength);
101 IsPhp1Keyword (LPCTSTR pszChars, int nLength)
103 return ISXKEYWORDI (s_apszPhp1KeywordList, pszChars, nLength);
107 IsPhp2Keyword (LPCTSTR pszChars, int nLength)
109 return ISXKEYWORDI (s_apszPhp2KeywordList, pszChars, nLength);
113 CrystalLineParser::ParseLinePhp (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
116 return dwCookie & (COOKIE_EXT_COMMENT|COOKIE_EXT_USER1);
118 bool bFirstChar = (dwCookie & ~(COOKIE_EXT_COMMENT|COOKIE_EXT_USER1)) == 0;
119 LPCTSTR pszCommentBegin = nullptr;
120 LPCTSTR pszCommentEnd = nullptr;
121 bool bRedefineBlock = true;
122 bool bDecIndex = false;
123 int nIdentBegin = -1;
126 for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
130 // CharNext did not advance, so we're at the end of the string
131 // and we already handled this character, so stop
140 if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
142 DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
144 else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
146 DEFINE_BLOCK (nPos, COLORINDEX_STRING);
148 else if (dwCookie & COOKIE_PREPROCESSOR)
150 DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
152 else if (dwCookie & COOKIE_EXT_USER1)
154 DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
158 if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.')
160 DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
164 DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
165 bRedefineBlock = true;
170 bRedefineBlock = false;
175 // Can be bigger than length if there is binary data
176 // See bug #1474782 Crash when comparing SQL with with binary data
177 if (I >= nLength || pszChars[I] == 0)
180 if (dwCookie & COOKIE_COMMENT)
182 DEFINE_BLOCK (I, COLORINDEX_COMMENT);
183 dwCookie |= COOKIE_COMMENT;
187 // String constant "...."
188 if (dwCookie & COOKIE_STRING)
190 if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
192 dwCookie &= ~COOKIE_STRING;
193 bRedefineBlock = true;
198 // Char constant '..'
199 if (dwCookie & COOKIE_CHAR)
201 if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
203 dwCookie &= ~COOKIE_CHAR;
204 bRedefineBlock = true;
209 // Extended comment <!--....-->
210 if (dwCookie & COOKIE_EXT_COMMENT)
212 if (dwCookie & COOKIE_EXT_USER1)
214 if ((pszCommentBegin < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))
216 dwCookie &= ~COOKIE_EXT_COMMENT;
217 bRedefineBlock = true;
218 pszCommentEnd = pszChars + I + 1;
223 if (I > 1 && pszChars[I] == '>' && pszChars[nPrevI] == '-' && *::CharPrev(pszChars, pszChars + nPrevI) == '-')
225 dwCookie &= ~COOKIE_EXT_COMMENT;
226 bRedefineBlock = true;
232 if ((dwCookie & COOKIE_EXT_USER1) && (pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/'))
234 DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
235 dwCookie |= COOKIE_COMMENT;
239 if ((dwCookie & COOKIE_EXT_USER1) && pszChars[I] == '#')
241 DEFINE_BLOCK (I, COLORINDEX_COMMENT);
242 dwCookie |= COOKIE_COMMENT;
246 // Extended comment <?....?>
247 if (dwCookie & COOKIE_EXT_USER1)
249 if (I > 0 && pszChars[I] == '>' && (pszChars[nPrevI] == '?' || pszChars[nPrevI] == '%'))
251 dwCookie &= ~COOKIE_EXT_USER1;
252 bRedefineBlock = true;
258 if ((dwCookie & (COOKIE_PREPROCESSOR|COOKIE_EXT_USER1)) && pszChars[I] == '"')
260 DEFINE_BLOCK (I, COLORINDEX_STRING);
261 dwCookie |= COOKIE_STRING;
265 if ((dwCookie & (COOKIE_PREPROCESSOR|COOKIE_EXT_USER1)) && pszChars[I] == '\'')
267 // 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] == '\'')
268 if (!I || !xisalnum (pszChars[nPrevI]))
270 DEFINE_BLOCK (I, COLORINDEX_STRING);
271 dwCookie |= COOKIE_CHAR;
276 if (dwCookie & COOKIE_EXT_USER1)
278 if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))
280 DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
281 dwCookie |= COOKIE_EXT_COMMENT;
282 pszCommentBegin = pszChars + I + 1;
288 if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength - 3 && pszChars[I] == '<' && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')
290 DEFINE_BLOCK (I, COLORINDEX_COMMENT);
292 dwCookie |= COOKIE_EXT_COMMENT;
293 dwCookie &= ~COOKIE_PREPROCESSOR;
300 if (!xisspace (pszChars[I]))
305 if (I < nLength && pszChars[I] == '<' && I < nLength - 1 && (pszChars[I + 1] == '?' || pszChars[I + 1] == '%'))
307 DEFINE_BLOCK (I, COLORINDEX_NORMALTEXT);
308 dwCookie |= COOKIE_EXT_USER1;
314 continue; // We don't need to extract keywords,
315 // for faster parsing skip the rest of loop
317 if (xisalnum (pszChars[I]) || pszChars[I] == '.')
319 if (nIdentBegin == -1)
324 if (nIdentBegin >= 0)
326 if (dwCookie & COOKIE_PREPROCESSOR)
328 if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
330 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
332 else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
334 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
336 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
338 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
345 else if (dwCookie & COOKIE_EXT_USER1)
347 if (dwCookie & COOKIE_USER2)
349 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
351 if (IsPhpKeyword (pszChars + nIdentBegin, I - nIdentBegin))
353 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
355 else if (IsPhp1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
357 DEFINE_BLOCK (nIdentBegin, COLORINDEX_OPERATOR);
359 else if (IsPhp2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
361 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
363 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
365 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
369 bool bFunction = false;
371 for (int j = I; j < nLength; j++)
373 if (!xisspace (pszChars[j]))
375 if (pszChars[j] == '(')
384 DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
392 else if (dwCookie & COOKIE_USER1)
394 if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
396 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
403 bRedefineBlock = true;
410 // Preprocessor start: < or bracket
411 if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength && pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-'))
413 DEFINE_BLOCK (I, COLORINDEX_OPERATOR);
414 DEFINE_BLOCK (I + 1, COLORINDEX_PREPROCESSOR);
415 dwCookie |= COOKIE_PREPROCESSOR;
421 if (dwCookie & COOKIE_EXT_USER1)
423 if (I > 0 && pszChars[I] == '>' && (pszChars[nPrevI] == '?' || pszChars[nPrevI] == '%'))
425 dwCookie &= ~COOKIE_EXT_USER1;
427 bRedefineBlock = true;
433 // Preprocessor end: > or bracket
434 if (dwCookie & COOKIE_PREPROCESSOR)
436 if (pszChars[I] == '>')
438 dwCookie &= ~COOKIE_PREPROCESSOR;
440 bRedefineBlock = true;
446 // Preprocessor start: &
447 if (!(dwCookie & COOKIE_EXT_USER1) && pszChars[I] == '&')
449 dwCookie |= COOKIE_USER1;
454 // Preprocessor end: ;
455 if (dwCookie & COOKIE_USER1)
457 if (pszChars[I] == ';')
459 dwCookie &= ~COOKIE_USER1;
465 // Preprocessor start: $
466 if ((dwCookie & COOKIE_EXT_USER1) && pszChars[I] == '$')
468 dwCookie |= COOKIE_USER2;
473 // Preprocessor end: ...
474 if (dwCookie & COOKIE_USER2)
476 if (!xisalnum (pszChars[I]))
478 dwCookie &= ~COOKIE_USER2;
486 if (nIdentBegin >= 0 && (dwCookie & COOKIE_PREPROCESSOR))
488 if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
490 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
492 else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
494 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
496 else if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
498 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
500 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
502 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
506 bool bFunction = false;
508 for (int j = I; j < nLength; j++)
510 if (!xisspace (pszChars[j]))
512 if (pszChars[j] == '(')
521 DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
525 else if (nIdentBegin >= 0 && (dwCookie & COOKIE_EXT_USER1))
527 if (IsPhpKeyword (pszChars + nIdentBegin, I - nIdentBegin))
529 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
531 else if (IsPhp1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
533 DEFINE_BLOCK (nIdentBegin, COLORINDEX_OPERATOR);
535 else if (IsPhp2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
537 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
539 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
541 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
545 bool bFunction = false;
547 for (int j = I; j < nLength; j++)
549 if (!xisspace (pszChars[j]))
551 if (pszChars[j] == '(')
560 DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
565 dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_PREPROCESSOR | COOKIE_EXT_USER1);