]>
Commit | Line | Data |
---|---|---|
b8b0e402 RD |
1 | // Scintilla source code edit control |
2 | /** @file LexCrontab.cxx | |
3 | ** Lexer to use with extended crontab files used by a powerful | |
4 | ** Windows scheduler/event monitor/automation manager nnCron. | |
a834585d | 5 | ** (http://nemtsev.eserv.ru/) |
b8b0e402 RD |
6 | **/ |
7 | // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> | |
8 | // The License.txt file describes the conditions under which this software may be distributed. | |
9 | ||
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
b8b0e402 RD |
12 | #include <stdio.h> |
13 | #include <stdarg.h> | |
1dcf666d RD |
14 | #include <assert.h> |
15 | #include <ctype.h> | |
b8b0e402 | 16 | |
1dcf666d | 17 | #include "ILexer.h" |
b8b0e402 RD |
18 | #include "Scintilla.h" |
19 | #include "SciLexer.h" | |
20 | ||
1dcf666d RD |
21 | #include "WordList.h" |
22 | #include "LexAccessor.h" | |
23 | #include "Accessor.h" | |
24 | #include "StyleContext.h" | |
25 | #include "CharacterSet.h" | |
26 | #include "LexerModule.h" | |
27 | ||
7e0c58e9 RD |
28 | #ifdef SCI_NAMESPACE |
29 | using namespace Scintilla; | |
30 | #endif | |
31 | ||
b8b0e402 RD |
32 | static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordList |
33 | *keywordLists[], Accessor &styler) | |
34 | { | |
35 | int state = SCE_NNCRONTAB_DEFAULT; | |
36 | char chNext = styler[startPos]; | |
37 | int lengthDoc = startPos + length; | |
38 | // create a buffer large enough to take the largest chunk... | |
39 | char *buffer = new char[length]; | |
40 | int bufferCount = 0; | |
41 | // used when highliting environment variables inside quoted string: | |
42 | bool insideString = false; | |
43 | ||
44 | // this assumes that we have 3 keyword list in conf.properties | |
45 | WordList §ion = *keywordLists[0]; | |
46 | WordList &keyword = *keywordLists[1]; | |
47 | WordList &modifier = *keywordLists[2]; | |
48 | ||
49 | // go through all provided text segment | |
50 | // using the hand-written state machine shown below | |
51 | styler.StartAt(startPos); | |
52 | styler.StartSegment(startPos); | |
53 | for (int i = startPos; i < lengthDoc; i++) { | |
54 | char ch = chNext; | |
55 | chNext = styler.SafeGetCharAt(i + 1); | |
56 | ||
57 | if (styler.IsLeadByte(ch)) { | |
58 | chNext = styler.SafeGetCharAt(i + 2); | |
59 | i++; | |
60 | continue; | |
61 | } | |
62 | switch(state) { | |
63 | case SCE_NNCRONTAB_DEFAULT: | |
64 | if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') { | |
65 | // whitespace is simply ignored here... | |
66 | styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); | |
67 | break; | |
68 | } else if( ch == '#' && styler.SafeGetCharAt(i+1) == '(') { | |
69 | // signals the start of a task... | |
70 | state = SCE_NNCRONTAB_TASK; | |
71 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
72 | } | |
9e730a78 | 73 | else if( ch == '\\' && (styler.SafeGetCharAt(i+1) == ' ' || |
a834585d | 74 | styler.SafeGetCharAt(i+1) == '\t')) { |
b8b0e402 RD |
75 | // signals the start of an extended comment... |
76 | state = SCE_NNCRONTAB_COMMENT; | |
77 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
78 | } else if( ch == '#' ) { | |
79 | // signals the start of a plain comment... | |
80 | state = SCE_NNCRONTAB_COMMENT; | |
81 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
82 | } else if( ch == ')' && styler.SafeGetCharAt(i+1) == '#') { | |
83 | // signals the end of a task... | |
84 | state = SCE_NNCRONTAB_TASK; | |
85 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
86 | } else if( ch == '"') { | |
87 | state = SCE_NNCRONTAB_STRING; | |
88 | styler.ColourTo(i,SCE_NNCRONTAB_STRING); | |
89 | } else if( ch == '%') { | |
90 | // signals environment variables | |
91 | state = SCE_NNCRONTAB_ENVIRONMENT; | |
92 | styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); | |
a834585d RD |
93 | } else if( ch == '<' && styler.SafeGetCharAt(i+1) == '%') { |
94 | // signals environment variables | |
95 | state = SCE_NNCRONTAB_ENVIRONMENT; | |
96 | styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); | |
b8b0e402 RD |
97 | } else if( ch == '*' ) { |
98 | // signals an asterisk | |
99 | // no state jump necessary for this simple case... | |
100 | styler.ColourTo(i,SCE_NNCRONTAB_ASTERISK); | |
1dcf666d | 101 | } else if( (isascii(ch) && isalpha(ch)) || ch == '<' ) { |
b8b0e402 RD |
102 | // signals the start of an identifier |
103 | bufferCount = 0; | |
104 | buffer[bufferCount++] = ch; | |
105 | state = SCE_NNCRONTAB_IDENTIFIER; | |
1dcf666d | 106 | } else if( isascii(ch) && isdigit(ch) ) { |
b8b0e402 RD |
107 | // signals the start of a number |
108 | bufferCount = 0; | |
109 | buffer[bufferCount++] = ch; | |
110 | state = SCE_NNCRONTAB_NUMBER; | |
111 | } else { | |
112 | // style it the default style.. | |
113 | styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); | |
114 | } | |
115 | break; | |
116 | ||
117 | case SCE_NNCRONTAB_COMMENT: | |
118 | // if we find a newline here, | |
119 | // we simply go to default state | |
120 | // else continue to work on it... | |
121 | if( ch == '\n' || ch == '\r' ) { | |
122 | state = SCE_NNCRONTAB_DEFAULT; | |
123 | } else { | |
124 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
125 | } | |
126 | break; | |
127 | ||
128 | case SCE_NNCRONTAB_TASK: | |
129 | // if we find a newline here, | |
130 | // we simply go to default state | |
131 | // else continue to work on it... | |
132 | if( ch == '\n' || ch == '\r' ) { | |
133 | state = SCE_NNCRONTAB_DEFAULT; | |
134 | } else { | |
135 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
136 | } | |
137 | break; | |
138 | ||
139 | case SCE_NNCRONTAB_STRING: | |
140 | if( ch == '%' ) { | |
141 | state = SCE_NNCRONTAB_ENVIRONMENT; | |
142 | insideString = true; | |
143 | styler.ColourTo(i-1,SCE_NNCRONTAB_STRING); | |
144 | break; | |
145 | } | |
146 | // if we find the end of a string char, we simply go to default state | |
147 | // else we're still dealing with an string... | |
148 | if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || | |
149 | (ch == '\n') || (ch == '\r') ) { | |
150 | state = SCE_NNCRONTAB_DEFAULT; | |
151 | } | |
152 | styler.ColourTo(i,SCE_NNCRONTAB_STRING); | |
153 | break; | |
154 | ||
155 | case SCE_NNCRONTAB_ENVIRONMENT: | |
156 | // if we find the end of a string char, we simply go to default state | |
157 | // else we're still dealing with an string... | |
158 | if( ch == '%' && insideString ) { | |
159 | state = SCE_NNCRONTAB_STRING; | |
160 | insideString = false; | |
161 | break; | |
162 | } | |
163 | if( (ch == '%' && styler.SafeGetCharAt(i-1)!='\\') | |
a834585d | 164 | || (ch == '\n') || (ch == '\r') || (ch == '>') ) { |
b8b0e402 RD |
165 | state = SCE_NNCRONTAB_DEFAULT; |
166 | styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); | |
167 | break; | |
168 | } | |
169 | styler.ColourTo(i+1,SCE_NNCRONTAB_ENVIRONMENT); | |
170 | break; | |
171 | ||
172 | case SCE_NNCRONTAB_IDENTIFIER: | |
173 | // stay in CONF_IDENTIFIER state until we find a non-alphanumeric | |
1dcf666d | 174 | if( (isascii(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || |
a834585d RD |
175 | (ch == '$') || (ch == '.') || (ch == '<') || (ch == '>') || |
176 | (ch == '@') ) { | |
b8b0e402 RD |
177 | buffer[bufferCount++] = ch; |
178 | } else { | |
179 | state = SCE_NNCRONTAB_DEFAULT; | |
180 | buffer[bufferCount] = '\0'; | |
181 | ||
182 | // check if the buffer contains a keyword, | |
183 | // and highlight it if it is a keyword... | |
184 | if(section.InList(buffer)) { | |
185 | styler.ColourTo(i,SCE_NNCRONTAB_SECTION ); | |
186 | } else if(keyword.InList(buffer)) { | |
187 | styler.ColourTo(i-1,SCE_NNCRONTAB_KEYWORD ); | |
188 | } // else if(strchr(buffer,'/') || strchr(buffer,'.')) { | |
189 | // styler.ColourTo(i-1,SCE_NNCRONTAB_EXTENSION); | |
190 | // } | |
191 | else if(modifier.InList(buffer)) { | |
192 | styler.ColourTo(i-1,SCE_NNCRONTAB_MODIFIER ); | |
193 | } else { | |
194 | styler.ColourTo(i-1,SCE_NNCRONTAB_DEFAULT); | |
195 | } | |
196 | // push back the faulty character | |
197 | chNext = styler[i--]; | |
198 | } | |
199 | break; | |
200 | ||
201 | case SCE_NNCRONTAB_NUMBER: | |
202 | // stay in CONF_NUMBER state until we find a non-numeric | |
1dcf666d | 203 | if( isascii(ch) && isdigit(ch) /* || ch == '.' */ ) { |
b8b0e402 RD |
204 | buffer[bufferCount++] = ch; |
205 | } else { | |
206 | state = SCE_NNCRONTAB_DEFAULT; | |
207 | buffer[bufferCount] = '\0'; | |
208 | // Colourize here... (normal number) | |
209 | styler.ColourTo(i-1,SCE_NNCRONTAB_NUMBER); | |
210 | // push back a character | |
211 | chNext = styler[i--]; | |
212 | } | |
213 | break; | |
214 | } | |
215 | } | |
1a2fb4cd | 216 | delete []buffer; |
b8b0e402 RD |
217 | } |
218 | ||
9e730a78 RD |
219 | static const char * const cronWordListDesc[] = { |
220 | "Section keywords and Forth words", | |
221 | "nnCrontab keywords", | |
222 | "Modifiers", | |
223 | 0 | |
224 | }; | |
225 | ||
226 | LexerModule lmNncrontab(SCLEX_NNCRONTAB, ColouriseNncrontabDoc, "nncrontab", 0, cronWordListDesc); |