OSDN Git Service

crystaledit: Organize the directory structure
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / parsers / sql.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:    sql.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 //  SQL 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 //  C++ keywords (MSVC5.0 + POET5.0)
27 static LPCTSTR s_apszSqlKeywordList[] =
28   {
29     _T ("all"),
30     _T ("and"),
31     _T ("by"),
32     _T ("distinct"),
33     _T ("from"),
34     _T ("group"),
35     _T ("in"),
36     _T ("insert"),
37     _T ("into"),
38     _T ("join"),
39     _T ("not"),
40     _T ("or"),
41     _T ("order"),
42     _T ("select"),
43     _T ("union"),
44     _T ("update"),
45     _T ("where"),
46   };
47
48 static LPCTSTR s_apszUser1KeywordList[] =
49   {
50     _T ("BYTE"),
51     _T ("CHAR"),
52     _T ("DATE"),
53     _T ("DOUBLE"),
54     _T ("INTEGER"),
55     _T ("MEMO"),
56     _T ("REAL"),
57     _T ("TIME"),
58     _T ("VARCHAR"),
59     _T ("WORD"),
60   };
61
62 static bool
63 IsSqlKeyword (LPCTSTR pszChars, int nLength)
64 {
65   return ISXKEYWORDI (s_apszSqlKeywordList, pszChars, nLength);
66 }
67
68 static bool
69 IsUser1Keyword (LPCTSTR pszChars, int nLength)
70 {
71   return ISXKEYWORDI (s_apszUser1KeywordList, pszChars, nLength);
72 }
73
74 DWORD
75 CrystalLineParser::ParseLineSql (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
76 {
77   if (nLength == 0)
78     return dwCookie & COOKIE_EXT_COMMENT;
79
80   bool bFirstChar = (dwCookie & ~COOKIE_EXT_COMMENT) == 0;
81   bool bRedefineBlock = true;
82   bool bWasCommentStart = false;
83   bool bDecIndex = false;
84   int nIdentBegin = -1;
85   int nPrevI = -1;
86   int I=0;
87   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
88     {
89       if (I == nPrevI)
90         {
91           // CharNext did not advance, so we're at the end of the string
92           // and we already handled this character, so stop
93           break;
94         }
95
96       if (bRedefineBlock)
97         {
98           int nPos = I;
99           if (bDecIndex)
100             nPos = nPrevI;
101           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
102             {
103               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
104             }
105           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
106             {
107               DEFINE_BLOCK (nPos, COLORINDEX_STRING);
108             }
109           else
110             {
111               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))
112                 {
113                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
114                 }
115               else
116                 {
117                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
118                   bRedefineBlock = true;
119                   bDecIndex = true;
120                   goto out;
121                 }
122             }
123           bRedefineBlock = false;
124           bDecIndex = false;
125         }
126 out:
127
128       // Can be bigger than length if there is binary data
129       // See bug #1474782 Crash when comparing SQL with with binary data
130       if (I >= nLength || pszChars[I] == 0)
131         break;
132
133       if (dwCookie & COOKIE_COMMENT)
134         {
135           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
136           dwCookie |= COOKIE_COMMENT;
137           break;
138         }
139
140       //  String constant "...."
141       if (dwCookie & COOKIE_STRING)
142         {
143           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
144             {
145               dwCookie &= ~COOKIE_STRING;
146               bRedefineBlock = true;
147             }
148           continue;
149         }
150
151       //  Char constant '..'
152       if (dwCookie & COOKIE_CHAR)
153         {
154           if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
155             {
156               dwCookie &= ~COOKIE_CHAR;
157               bRedefineBlock = true;
158             }
159           continue;
160         }
161
162       //  Extended comment /*....*/
163       if (dwCookie & COOKIE_EXT_COMMENT)
164         {
165           // if (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '*')
166           if ((I > 1 && pszChars[I] == '/' && pszChars[nPrevI] == '*' /*&& *::CharPrev(pszChars, pszChars + nPrevI) != '/'*/ && !bWasCommentStart) || (I == 1 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))
167             {
168               dwCookie &= ~COOKIE_EXT_COMMENT;
169               bRedefineBlock = true;
170             }
171           bWasCommentStart = false;
172           continue;
173         }
174
175       if (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/')
176         {
177           DEFINE_BLOCK (I - 1, COLORINDEX_COMMENT);
178           dwCookie |= COOKIE_COMMENT;
179           break;
180         }
181
182       //  Normal text
183       if (pszChars[I] == '"')
184         {
185           DEFINE_BLOCK (I, COLORINDEX_STRING);
186           dwCookie |= COOKIE_STRING;
187           continue;
188         }
189       if (pszChars[I] == '\'')
190         {
191           // 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] == '\'')
192           if (!I || !xisalnum (pszChars[nPrevI]))
193             {
194               DEFINE_BLOCK (I, COLORINDEX_STRING);
195               dwCookie |= COOKIE_CHAR;
196               continue;
197             }
198         }
199       if (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/')
200         {
201           DEFINE_BLOCK (I - 1, COLORINDEX_COMMENT);
202           dwCookie |= COOKIE_EXT_COMMENT;
203           bWasCommentStart = true;
204           continue;
205         }
206
207       bWasCommentStart = false;
208
209       if (bFirstChar)
210         {
211           if (!xisspace (pszChars[I]))
212             bFirstChar = false;
213         }
214
215       if (pBuf == nullptr)
216         continue;               //  We don't need to extract keywords,
217       //  for faster parsing skip the rest of loop
218
219       if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))
220         {
221           if (nIdentBegin == -1)
222             nIdentBegin = I;
223         }
224       else
225         {
226           if (nIdentBegin >= 0)
227             {
228               if (IsSqlKeyword (pszChars + nIdentBegin, I - nIdentBegin))
229                 {
230                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
231                 }
232               else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
233                 {
234                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
235                 }
236               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
237                 {
238                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
239                 }
240               else
241                 {
242                   bool bFunction = false;
243
244                   for (int j = I; j < nLength; j++)
245                     {
246                       if (!xisspace (pszChars[j]))
247                         {
248                           if (pszChars[j] == '(')
249                             {
250                               bFunction = true;
251                             }
252                           break;
253                         }
254                     }
255                   if (bFunction)
256                     {
257                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
258                     }
259                 }
260               bRedefineBlock = true;
261               bDecIndex = true;
262               nIdentBegin = -1;
263             }
264         }
265     }
266
267   if (nIdentBegin >= 0)
268     {
269       if (IsSqlKeyword (pszChars + nIdentBegin, I - nIdentBegin))
270         {
271           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
272         }
273       else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
274         {
275           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
276         }
277       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
278         {
279           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
280         }
281       else
282         {
283           bool bFunction = false;
284
285           for (int j = I; j < nLength; j++)
286             {
287               if (!xisspace (pszChars[j]))
288                 {
289                   if (pszChars[j] == '(')
290                     {
291                       bFunction = true;
292                     }
293                   break;
294                 }
295             }
296           if (bFunction)
297             {
298               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
299             }
300         }
301     }
302
303   if (pszChars[nLength - 1] != '\\' || IsMBSTrail(pszChars, nLength - 1))
304     dwCookie &= COOKIE_EXT_COMMENT;
305   return dwCookie;
306 }