~ubuntu-branches/ubuntu/utopic/geany/utopic

« back to all changes in this revision

Viewing changes to scintilla/LexSQL.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Scintilla source code edit control
2
 
/** @file LexSQL.cxx
3
 
 ** Lexer for SQL, including PL/SQL and SQL*Plus.
4
 
 **/
5
 
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
6
 
// The License.txt file describes the conditions under which this software may be distributed.
7
 
 
8
 
#include <stdlib.h>
9
 
#include <string.h>
10
 
#include <ctype.h>
11
 
#include <stdio.h>
12
 
#include <stdarg.h>
13
 
 
14
 
#include "Platform.h"
15
 
 
16
 
#include "PropSet.h"
17
 
#include "Accessor.h"
18
 
#include "StyleContext.h"
19
 
#include "KeyWords.h"
20
 
#include "Scintilla.h"
21
 
#include "SciLexer.h"
22
 
 
23
 
#ifdef SCI_NAMESPACE
24
 
using namespace Scintilla;
25
 
#endif
26
 
 
27
 
static inline bool IsAWordChar(int ch) {
28
 
        return (ch < 0x80) && (isalnum(ch) || ch == '_');
29
 
}
30
 
 
31
 
static inline bool IsAWordStart(int ch) {
32
 
        return (ch < 0x80) && (isalpha(ch) || ch == '_');
33
 
}
34
 
 
35
 
static inline bool IsADoxygenChar(int ch) {
36
 
        return (islower(ch) || ch == '$' || ch == '@' ||
37
 
                ch == '\\' || ch == '&' || ch == '<' ||
38
 
                ch == '>' || ch == '#' || ch == '{' ||
39
 
                ch == '}' || ch == '[' || ch == ']');
40
 
}
41
 
 
42
 
static inline bool IsANumberChar(int ch) {
43
 
        // Not exactly following number definition (several dots are seen as OK, etc.)
44
 
        // but probably enough in most cases.
45
 
        return (ch < 0x80) &&
46
 
                (isdigit(ch) || toupper(ch) == 'E' ||
47
 
             ch == '.' || ch == '-' || ch == '+');
48
 
}
49
 
 
50
 
static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
51
 
                            Accessor &styler) {
52
 
 
53
 
        WordList &keywords1 = *keywordlists[0];
54
 
        WordList &keywords2 = *keywordlists[1];
55
 
        WordList &kw_pldoc = *keywordlists[2];
56
 
        WordList &kw_sqlplus = *keywordlists[3];
57
 
        WordList &kw_user1 = *keywordlists[4];
58
 
        WordList &kw_user2 = *keywordlists[5];
59
 
        WordList &kw_user3 = *keywordlists[6];
60
 
        WordList &kw_user4 = *keywordlists[7];
61
 
 
62
 
        StyleContext sc(startPos, length, initStyle, styler);
63
 
 
64
 
        // property sql.backslash.escapes 
65
 
        //      Enables backslash as an escape character in SQL. 
66
 
        bool sqlBackslashEscapes = styler.GetPropertyInt("sql.backslash.escapes", 0) != 0;
67
 
 
68
 
        bool sqlBackticksIdentifier = styler.GetPropertyInt("lexer.sql.backticks.identifier", 0) != 0;
69
 
        int styleBeforeDCKeyword = SCE_SQL_DEFAULT;
70
 
        for (; sc.More(); sc.Forward()) {
71
 
                // Determine if the current state should terminate.
72
 
                switch (sc.state) {
73
 
                case SCE_SQL_OPERATOR:
74
 
                        sc.SetState(SCE_SQL_DEFAULT);
75
 
                        break;
76
 
                case SCE_SQL_NUMBER:
77
 
                        // We stop the number definition on non-numerical non-dot non-eE non-sign char
78
 
                        if (!IsANumberChar(sc.ch)) {
79
 
                                sc.SetState(SCE_SQL_DEFAULT);
80
 
                        }
81
 
                        break;
82
 
                case SCE_SQL_IDENTIFIER:
83
 
                        if (!IsAWordChar(sc.ch)) {
84
 
                                int nextState = SCE_SQL_DEFAULT;
85
 
                                char s[1000];
86
 
                                sc.GetCurrentLowered(s, sizeof(s));
87
 
                                if (keywords1.InList(s)) {
88
 
                                        sc.ChangeState(SCE_SQL_WORD);
89
 
                                } else if (keywords2.InList(s)) {
90
 
                                        sc.ChangeState(SCE_SQL_WORD2);
91
 
                                } else if (kw_sqlplus.InListAbbreviated(s, '~')) {
92
 
                                        sc.ChangeState(SCE_SQL_SQLPLUS);
93
 
                                        if (strncmp(s, "rem", 3) == 0) {
94
 
                                                nextState = SCE_SQL_SQLPLUS_COMMENT;
95
 
                                        } else if (strncmp(s, "pro", 3) == 0) {
96
 
                                                nextState = SCE_SQL_SQLPLUS_PROMPT;
97
 
                                        }
98
 
                                } else if (kw_user1.InList(s)) {
99
 
                                        sc.ChangeState(SCE_SQL_USER1);
100
 
                                } else if (kw_user2.InList(s)) {
101
 
                                        sc.ChangeState(SCE_SQL_USER2);
102
 
                                } else if (kw_user3.InList(s)) {
103
 
                                        sc.ChangeState(SCE_SQL_USER3);
104
 
                                } else if (kw_user4.InList(s)) {
105
 
                                        sc.ChangeState(SCE_SQL_USER4);
106
 
                                }
107
 
                                sc.SetState(nextState);
108
 
                        }
109
 
                        break;
110
 
                case SCE_SQL_QUOTEDIDENTIFIER:
111
 
                        if (sc.ch == 0x60) {
112
 
                                if (sc.chNext == 0x60) {
113
 
                                        sc.Forward();   // Ignore it
114
 
                                } else {
115
 
                                        sc.ForwardSetState(SCE_SQL_DEFAULT);
116
 
                                }
117
 
                        }
118
 
                        break;
119
 
                case SCE_SQL_COMMENT:
120
 
                        if (sc.Match('*', '/')) {
121
 
                                sc.Forward();
122
 
                                sc.ForwardSetState(SCE_SQL_DEFAULT);
123
 
                        }
124
 
                        break;
125
 
                case SCE_SQL_COMMENTDOC:
126
 
                        if (sc.Match('*', '/')) {
127
 
                                sc.Forward();
128
 
                                sc.ForwardSetState(SCE_SQL_DEFAULT);
129
 
                        } else if (sc.ch == '@' || sc.ch == '\\') { // Doxygen support
130
 
                                // Verify that we have the conditions to mark a comment-doc-keyword
131
 
                                if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
132
 
                                        styleBeforeDCKeyword = SCE_SQL_COMMENTDOC;
133
 
                                        sc.SetState(SCE_SQL_COMMENTDOCKEYWORD);
134
 
                                }
135
 
                        }
136
 
                        break;
137
 
                case SCE_SQL_COMMENTLINE:
138
 
                case SCE_SQL_COMMENTLINEDOC:
139
 
                case SCE_SQL_SQLPLUS_COMMENT:
140
 
                case SCE_SQL_SQLPLUS_PROMPT:
141
 
                        if (sc.atLineStart) {
142
 
                                sc.SetState(SCE_SQL_DEFAULT);
143
 
                        }
144
 
                        break;
145
 
                case SCE_SQL_COMMENTDOCKEYWORD:
146
 
                        if ((styleBeforeDCKeyword == SCE_SQL_COMMENTDOC) && sc.Match('*', '/')) {
147
 
                                sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR);
148
 
                                sc.Forward();
149
 
                                sc.ForwardSetState(SCE_SQL_DEFAULT);
150
 
                        } else if (!IsADoxygenChar(sc.ch)) {
151
 
                                char s[100];
152
 
                                sc.GetCurrentLowered(s, sizeof(s));
153
 
                                if (!isspace(sc.ch) || !kw_pldoc.InList(s + 1)) {
154
 
                                        sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR);
155
 
                                }
156
 
                                sc.SetState(styleBeforeDCKeyword);
157
 
                        }
158
 
                        break;
159
 
                case SCE_SQL_CHARACTER:
160
 
                        if (sqlBackslashEscapes && sc.ch == '\\') {
161
 
                                sc.Forward();
162
 
                        } else if (sc.ch == '\'') {
163
 
                                if (sc.chNext == '\"') {
164
 
                                        sc.Forward();
165
 
                                } else {
166
 
                                        sc.ForwardSetState(SCE_SQL_DEFAULT);
167
 
                                }
168
 
                        }
169
 
                        break;
170
 
                case SCE_SQL_STRING:
171
 
                        if (sc.ch == '\\') {
172
 
                                // Escape sequence
173
 
                                sc.Forward();
174
 
                        } else if (sc.ch == '\"') {
175
 
                                if (sc.chNext == '\"') {
176
 
                                        sc.Forward();
177
 
                                } else {
178
 
                                        sc.ForwardSetState(SCE_SQL_DEFAULT);
179
 
                                }
180
 
                        }
181
 
                        break;
182
 
                }
183
 
 
184
 
                // Determine if a new state should be entered.
185
 
                if (sc.state == SCE_SQL_DEFAULT) {
186
 
                        if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
187
 
                                sc.SetState(SCE_SQL_NUMBER);
188
 
                        } else if (IsAWordStart(sc.ch)) {
189
 
                                sc.SetState(SCE_SQL_IDENTIFIER);
190
 
                        } else if (sc.ch == 0x60 && sqlBackticksIdentifier) {
191
 
                                sc.SetState(SCE_SQL_QUOTEDIDENTIFIER);
192
 
                        } else if (sc.Match('/', '*')) {
193
 
                                if (sc.Match("/**") || sc.Match("/*!")) {       // Support of Doxygen doc. style
194
 
                                        sc.SetState(SCE_SQL_COMMENTDOC);
195
 
                                } else {
196
 
                                        sc.SetState(SCE_SQL_COMMENT);
197
 
                                }
198
 
                                sc.Forward();   // Eat the * so it isn't used for the end of the comment
199
 
                        } else if (sc.Match('-', '-')) {
200
 
                                // MySQL requires a space or control char after --
201
 
                                // http://dev.mysql.com/doc/mysql/en/ansi-diff-comments.html
202
 
                                // Perhaps we should enforce that with proper property:
203
 
//~                     } else if (sc.Match("-- ")) {
204
 
                                sc.SetState(SCE_SQL_COMMENTLINE);
205
 
                        } else if (sc.ch == '#') {
206
 
                                sc.SetState(SCE_SQL_COMMENTLINEDOC);
207
 
                        } else if (sc.ch == '\'') {
208
 
                                sc.SetState(SCE_SQL_CHARACTER);
209
 
                        } else if (sc.ch == '\"') {
210
 
                                sc.SetState(SCE_SQL_STRING);
211
 
                        } else if (isoperator(static_cast<char>(sc.ch))) {
212
 
                                sc.SetState(SCE_SQL_OPERATOR);
213
 
                        }
214
 
                }
215
 
        }
216
 
        sc.Complete();
217
 
}
218
 
 
219
 
static bool IsStreamCommentStyle(int style) {
220
 
        return style == SCE_SQL_COMMENT ||
221
 
               style == SCE_SQL_COMMENTDOC ||
222
 
               style == SCE_SQL_COMMENTDOCKEYWORD ||
223
 
               style == SCE_SQL_COMMENTDOCKEYWORDERROR;
224
 
}
225
 
 
226
 
// Store both the current line's fold level and the next lines in the
227
 
// level store to make it easy to pick up with each increment.
228
 
static void FoldSQLDoc(unsigned int startPos, int length, int initStyle,
229
 
                            WordList *[], Accessor &styler) {
230
 
        bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
231
 
        bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
232
 
        bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0;
233
 
 
234
 
        // property fold.sql.exists 
235
 
        //      Enables "EXISTS" to end a fold as is started by "IF" in "DROP TABLE IF EXISTS". 
236
 
        bool foldSqlExists = styler.GetPropertyInt("fold.sql.exists", 1) != 0;
237
 
 
238
 
        unsigned int endPos = startPos + length;
239
 
        int visibleChars = 0;
240
 
        int lineCurrent = styler.GetLine(startPos);
241
 
        int levelCurrent = SC_FOLDLEVELBASE;
242
 
        if (lineCurrent > 0) {
243
 
                levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
244
 
        }
245
 
        int levelNext = levelCurrent;
246
 
        char chNext = styler[startPos];
247
 
        int styleNext = styler.StyleAt(startPos);
248
 
        int style = initStyle;
249
 
        bool endFound = false;
250
 
        for (unsigned int i = startPos; i < endPos; i++) {
251
 
                char ch = chNext;
252
 
                chNext = styler.SafeGetCharAt(i + 1);
253
 
                int stylePrev = style;
254
 
                style = styleNext;
255
 
                styleNext = styler.StyleAt(i + 1);
256
 
                bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
257
 
                if (foldComment && IsStreamCommentStyle(style)) {
258
 
                        if (!IsStreamCommentStyle(stylePrev)) {
259
 
                                levelNext++;
260
 
                        } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
261
 
                                // Comments don't end at end of line and the next character may be unstyled.
262
 
                                levelNext--;
263
 
                        }
264
 
                }
265
 
                if (foldComment && (style == SCE_SQL_COMMENTLINE)) {
266
 
                        // MySQL needs -- comments to be followed by space or control char
267
 
                        if ((ch == '-') && (chNext == '-')) {
268
 
                                char chNext2 = styler.SafeGetCharAt(i + 2);
269
 
                                char chNext3 = styler.SafeGetCharAt(i + 3);
270
 
                                if (chNext2 == '{' || chNext3 == '{') {
271
 
                                        levelNext++;
272
 
                                } else if (chNext2 == '}' || chNext3 == '}') {
273
 
                                        levelNext--;
274
 
                                }
275
 
                        }
276
 
                }
277
 
                if (style == SCE_SQL_OPERATOR) {
278
 
                        if (ch == '(') {
279
 
                                levelNext++;
280
 
                        } else if (ch == ')') {
281
 
                                levelNext--;
282
 
                        }
283
 
                }
284
 
                // If new keyword (cannot trigger on elseif or nullif, does less tests)
285
 
                if (style == SCE_SQL_WORD && stylePrev != SCE_SQL_WORD) {
286
 
                        const int MAX_KW_LEN = 6;       // Maximum length of folding keywords
287
 
                        char s[MAX_KW_LEN + 2];
288
 
                        unsigned int j = 0;
289
 
                        for (; j < MAX_KW_LEN + 1; j++) {
290
 
                                if (!iswordchar(styler[i + j])) {
291
 
                                        break;
292
 
                                }
293
 
                                s[j] = static_cast<char>(tolower(styler[i + j]));
294
 
                        }
295
 
                        if (j == MAX_KW_LEN + 1) {
296
 
                                // Keyword too long, don't test it
297
 
                                s[0] = '\0';
298
 
                        } else {
299
 
                                s[j] = '\0';
300
 
                        }
301
 
                        if ((!foldOnlyBegin) && (strcmp(s, "if") == 0 || strcmp(s, "loop") == 0)) {
302
 
                                if (endFound) {
303
 
                                        // ignore
304
 
                                        endFound = false;
305
 
                                } else {
306
 
                                        levelNext++;
307
 
                                }
308
 
                        } else if (strcmp(s, "begin") == 0) {
309
 
                                levelNext++;
310
 
                        } else if ((strcmp(s, "end") == 0) ||
311
 
//                                              // DROP TABLE IF EXISTS or CREATE TABLE IF NOT EXISTS
312
 
                                                (foldSqlExists && (strcmp(s, "exists") == 0)) ||
313
 
//                                              //  SQL Anywhere permits IF ... ELSE ... ENDIF
314
 
//                                              //      will only be active if "endif" appears in the 
315
 
//                                              //              keyword list.
316
 
                                                (strcmp(s, "endif") == 0)) {
317
 
                                endFound = true;
318
 
                                levelNext--;
319
 
                                if (levelNext < SC_FOLDLEVELBASE) {
320
 
                                        levelNext = SC_FOLDLEVELBASE;
321
 
                                }
322
 
                        }
323
 
                }
324
 
                if (atEOL) {
325
 
                        int levelUse = levelCurrent;
326
 
                        int lev = levelUse | levelNext << 16;
327
 
                        if (visibleChars == 0 && foldCompact)
328
 
                                lev |= SC_FOLDLEVELWHITEFLAG;
329
 
                        if (levelUse < levelNext)
330
 
                                lev |= SC_FOLDLEVELHEADERFLAG;
331
 
                        if (lev != styler.LevelAt(lineCurrent)) {
332
 
                                styler.SetLevel(lineCurrent, lev);
333
 
                        }
334
 
                        lineCurrent++;
335
 
                        levelCurrent = levelNext;
336
 
                        visibleChars = 0;
337
 
                        endFound = false;
338
 
                }
339
 
                if (!isspacechar(ch)) {
340
 
                        visibleChars++;
341
 
                }
342
 
        }
343
 
}
344
 
 
345
 
static const char * const sqlWordListDesc[] = {
346
 
        "Keywords",
347
 
        "Database Objects",
348
 
        "PLDoc",
349
 
        "SQL*Plus",
350
 
        "User Keywords 1",
351
 
        "User Keywords 2",
352
 
        "User Keywords 3",
353
 
        "User Keywords 4",
354
 
        0
355
 
};
356
 
 
357
 
LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", FoldSQLDoc, sqlWordListDesc);