OSDN Git Service

crystaledit: Make almost the same code into a common function
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / css.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:       css.cpp
3 //  Version:    1.0
4 //  Created:    22-Oct-2006
5 //
6 //  Copyright:  Stcherbatchenko Andrei, portions by Tim Gerundt
7 //  E-mail:     windfall@gmx.de
8 //
9 //  CSS (Cascading Stylesheets) 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 "string_util.h"
21
22 #ifdef _DEBUG
23 #define new DEBUG_NEW
24 #endif
25
26 static LPTSTR s_apszCss1KeywordList[] =
27   {
28     // CSS 1
29     _T ("background"),
30     _T ("background-attachment"),
31     _T ("background-color"),
32     _T ("background-image"),
33     _T ("background-position"),
34     _T ("background-repeat"),
35     _T ("border"),
36     _T ("border-bottom"),
37     _T ("border-bottom-width"),
38     _T ("border-color"),
39     _T ("border-left"),
40     _T ("border-left-width"),
41     _T ("border-right"),
42     _T ("border-right-width"),
43     _T ("border-style"),
44     _T ("border-top"),
45     _T ("border-top-width"),
46     _T ("border-width"),
47     _T ("clear"),
48     _T ("color"),
49     _T ("display"),
50     _T ("float"),
51     _T ("font"),
52     _T ("font-family"),
53     _T ("font-size"),
54     _T ("font-style"),
55     _T ("font-variant"),
56     _T ("font-weight"),
57     _T ("height"),
58     _T ("letter-spacing"),
59     _T ("line-height"),
60     _T ("list-style"),
61     _T ("list-style-image"),
62     _T ("list-style-position"),
63     _T ("list-style-type"),
64     _T ("margin"),
65     _T ("margin-bottom"),
66     _T ("margin-left"),
67     _T ("margin-right"),
68     _T ("margin-top"),
69     _T ("padding"),
70     _T ("padding-bottom"),
71     _T ("padding-left"),
72     _T ("padding-right"),
73     _T ("padding-top"),
74     _T ("text-align"),
75     _T ("text-decoration"),
76     _T ("text-indent"),
77     _T ("text-transform"),
78     _T ("vertical-align"),
79     _T ("white-space"),
80     _T ("width"),
81     _T ("word-spacing"),
82     nullptr
83   };
84
85 static LPTSTR s_apszCss2KeywordList[] =
86   {
87     // CSS 2
88     _T ("ascent"),
89     _T ("azimuth"),
90     _T ("baseline"),
91     _T ("bbox"),
92     _T ("border-bottom-color"),
93     _T ("border-bottom-style"),
94     _T ("border-collapse"),
95     _T ("border-color"),
96     _T ("border-left-color"),
97     _T ("border-left-style"),
98     _T ("border-right-color"),
99     _T ("border-right-style"),
100     _T ("border-spacing"),
101     _T ("border-style"),
102     _T ("border-top-color"),
103     _T ("border-top-style"),
104     _T ("bottom"),
105     _T ("cap-height"),
106     _T ("caption-side"),
107     _T ("centerline"),
108     _T ("clip"),
109     _T ("content"),
110     _T ("counter-increment"),
111     _T ("counter-reset"),
112     _T ("cue"),
113     _T ("cue-after"),
114     _T ("cue-before"),
115     _T ("cursor"),
116     _T ("definition-src"),
117     _T ("descent"),
118     _T ("direction"),
119     _T ("elevation"),
120     _T ("empty-cells"),
121     _T ("font-size-adjust"),
122     _T ("font-stretch"),
123     _T ("left"),
124     _T ("marker-offset"),
125     _T ("marks"),
126     _T ("mathline"),
127     _T ("max-height"),
128     _T ("max-width"),
129     _T ("min-height"),
130     _T ("min-width"),
131     _T ("orphans"),
132     _T ("outline"),
133     _T ("outline-color"),
134     _T ("outline-style"),
135     _T ("outline-width"),
136     _T ("overflow"),
137     _T ("page"),
138     _T ("page-break-after"),
139     _T ("page-break-before"),
140     _T ("page-break-inside"),
141     _T ("panose-1"),
142     _T ("pause"),
143     _T ("pause-after"),
144     _T ("pause-before"),
145     _T ("pitch"),
146     _T ("pitch-range"),
147     _T ("play-during"),
148     _T ("position"),
149     _T ("quotes"),
150     _T ("richness"),
151     _T ("right"),
152     _T ("size"),
153     _T ("slope"),
154     _T ("speak"),
155     _T ("speak-header"),
156     _T ("speak-numeral"),
157     _T ("speak-punctuation"),
158     _T ("speech-rate"),
159     _T ("src"),
160     _T ("stemh"),
161     _T ("stemv"),
162     _T ("stress"),
163     _T ("table-layout"),
164     _T ("text-shadow"),
165     _T ("top"),
166     _T ("topline"),
167     _T ("unicode-bidi"),
168     _T ("unicode-range"),
169     _T ("units-per-em"),
170     _T ("visibility"),
171     _T ("voice-family"),
172     _T ("volume"),
173     _T ("widows"),
174     _T ("widths"),
175     _T ("x-height"),
176     _T ("z-index"),
177     nullptr
178   };
179
180 static bool
181 IsXKeyword (LPTSTR apszKeywords[], LPCTSTR pszChars, int nLength)
182 {
183   for (int L = 0; apszKeywords[L] != nullptr; L++)
184     {
185       if (_tcsnicmp (apszKeywords[L], pszChars, nLength) == 0
186             && apszKeywords[L][nLength] == 0)
187         return true;
188     }
189   return false;
190 }
191
192 static bool
193 IsCss1Keyword (LPCTSTR pszChars, int nLength)
194 {
195   return IsXKeyword (s_apszCss1KeywordList, pszChars, nLength);
196 }
197
198 static bool
199 IsCss2Keyword (LPCTSTR pszChars, int nLength)
200 {
201   return IsXKeyword (s_apszCss2KeywordList, pszChars, nLength);
202 }
203
204 DWORD
205 CrystalLineParser::ParseLineCss (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
206 {
207   if (nLength == 0)
208     return dwCookie & (COOKIE_EXT_COMMENT|COOKIE_EXT_DEFINITION|COOKIE_EXT_VALUE);
209
210   bool bFirstChar = (dwCookie & ~(COOKIE_EXT_COMMENT|COOKIE_EXT_DEFINITION|COOKIE_EXT_VALUE)) == 0;
211   bool bRedefineBlock = true;
212   bool bWasCommentStart = false;
213   bool bDecIndex = false;
214   int nIdentBegin = -1;
215   int nPrevI = -1;
216   int I=0;
217   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
218     {
219       if (I == nPrevI)
220         {
221           // CharNext did not advance, so we're at the end of the string
222           // and we already handled this character, so stop
223           break;
224         }
225
226       if (bRedefineBlock)
227         {
228           int nPos = I;
229           if (bDecIndex)
230             nPos = nPrevI;
231           if (dwCookie & COOKIE_EXT_COMMENT)
232             {
233               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
234             }
235           else
236             {
237               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' || pszChars[nPos] == '-' || pszChars[nPos] == '%')
238                 {
239                   if (dwCookie & COOKIE_EXT_VALUE)
240                     {
241                       DEFINE_BLOCK (nPos, COLORINDEX_STRING);
242                     }
243                   else
244                     {
245                       DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
246                     }
247                 }
248               else
249                 {
250                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
251                   bRedefineBlock = true;
252                   bDecIndex = true;
253                   goto out;
254                 }
255             }
256           bRedefineBlock = false;
257           bDecIndex = false;
258         }
259 out:
260
261       // Can be bigger than length if there is binary data
262       // See bug #1474782 Crash when comparing SQL with with binary data
263       if (I >= nLength)
264         break;
265
266       //  Extended definition {....}
267       if (dwCookie & COOKIE_EXT_DEFINITION)
268         {
269           if (pszChars[I] == ':') //Value start...
270             {
271               dwCookie |= COOKIE_EXT_VALUE;
272             }
273           else if (pszChars[I] == ';') //Value end...
274             {
275               dwCookie &= ~COOKIE_EXT_VALUE;
276             }
277           else if (pszChars[I] == '}') //Definition end...
278             {
279               dwCookie &= ~COOKIE_EXT_DEFINITION;
280               dwCookie &= ~COOKIE_EXT_VALUE;
281             }
282         }
283
284       //  Extended comment /*....*/
285       if (dwCookie & COOKIE_EXT_COMMENT)
286         {
287           if ((I > 1 && pszChars[I] == '/' && pszChars[nPrevI] == '*' && !bWasCommentStart) || (I == 1 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))
288             {
289               dwCookie &= ~COOKIE_EXT_COMMENT;
290               bRedefineBlock = true;
291             }
292           bWasCommentStart = false;
293           continue;
294         }
295
296       //  Normal text
297       if (pszChars[I] == '{')
298         {
299           dwCookie |= COOKIE_EXT_DEFINITION;
300         }
301       if (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/')
302         {
303           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
304           dwCookie |= COOKIE_EXT_COMMENT;
305           bWasCommentStart = true;
306           continue;
307         }
308
309       bWasCommentStart = false;
310
311       if (bFirstChar)
312         {
313           if (!xisspace (pszChars[I]))
314             bFirstChar = false;
315         }
316
317       if (pBuf == nullptr)
318         continue;               //  We don't need to extract keywords,
319       //  for faster parsing skip the rest of loop
320
321       if (xisalnum (pszChars[I]) || pszChars[I] == '.' || pszChars[I] == '-' || pszChars[I] == '%')
322         {
323           if (nIdentBegin == -1)
324             nIdentBegin = I;
325         }
326       else
327         {
328           if (nIdentBegin >= 0)
329             {
330               if (dwCookie & COOKIE_EXT_VALUE)
331                 {
332                   if (IsCss1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
333                     {
334                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
335                     }
336                   else if (IsCss2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
337                     {
338                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
339                     }
340                   else
341                     {
342                       goto next;
343                     }
344                 }
345               bRedefineBlock = true;
346               bDecIndex = true;
347               nIdentBegin = -1;
348 next:
349               ;
350             }
351         }
352     }
353
354   if ((nIdentBegin >= 0) && (dwCookie & COOKIE_EXT_VALUE))
355     {
356       if (IsCss1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
357         {
358           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
359         }
360       else if (IsCss2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
361         {
362           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
363         }
364     }
365
366   dwCookie &= (COOKIE_EXT_COMMENT|COOKIE_EXT_DEFINITION|COOKIE_EXT_VALUE);
367   return dwCookie;
368 }