]>
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. | |
5 | ** (http://nemtsev.virtualave.net/) | |
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> | |
12 | #include <ctype.h> | |
13 | #include <stdio.h> | |
14 | #include <stdarg.h> | |
15 | ||
16 | #include "Platform.h" | |
17 | ||
18 | #include "PropSet.h" | |
19 | #include "Accessor.h" | |
20 | #include "KeyWords.h" | |
21 | #include "Scintilla.h" | |
22 | #include "SciLexer.h" | |
23 | ||
24 | static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordList | |
25 | *keywordLists[], Accessor &styler) | |
26 | { | |
27 | int state = SCE_NNCRONTAB_DEFAULT; | |
28 | char chNext = styler[startPos]; | |
29 | int lengthDoc = startPos + length; | |
30 | // create a buffer large enough to take the largest chunk... | |
31 | char *buffer = new char[length]; | |
32 | int bufferCount = 0; | |
33 | // used when highliting environment variables inside quoted string: | |
34 | bool insideString = false; | |
35 | ||
36 | // this assumes that we have 3 keyword list in conf.properties | |
37 | WordList §ion = *keywordLists[0]; | |
38 | WordList &keyword = *keywordLists[1]; | |
39 | WordList &modifier = *keywordLists[2]; | |
40 | ||
41 | // go through all provided text segment | |
42 | // using the hand-written state machine shown below | |
43 | styler.StartAt(startPos); | |
44 | styler.StartSegment(startPos); | |
45 | for (int i = startPos; i < lengthDoc; i++) { | |
46 | char ch = chNext; | |
47 | chNext = styler.SafeGetCharAt(i + 1); | |
48 | ||
49 | if (styler.IsLeadByte(ch)) { | |
50 | chNext = styler.SafeGetCharAt(i + 2); | |
51 | i++; | |
52 | continue; | |
53 | } | |
54 | switch(state) { | |
55 | case SCE_NNCRONTAB_DEFAULT: | |
56 | if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') { | |
57 | // whitespace is simply ignored here... | |
58 | styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); | |
59 | break; | |
60 | } else if( ch == '#' && styler.SafeGetCharAt(i+1) == '(') { | |
61 | // signals the start of a task... | |
62 | state = SCE_NNCRONTAB_TASK; | |
63 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
64 | } | |
65 | else if( ch == '\\' && styler.SafeGetCharAt(i+1) == ' ') { | |
66 | // signals the start of an extended comment... | |
67 | state = SCE_NNCRONTAB_COMMENT; | |
68 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
69 | } else if( ch == '#' ) { | |
70 | // signals the start of a plain comment... | |
71 | state = SCE_NNCRONTAB_COMMENT; | |
72 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
73 | } else if( ch == ')' && styler.SafeGetCharAt(i+1) == '#') { | |
74 | // signals the end of a task... | |
75 | state = SCE_NNCRONTAB_TASK; | |
76 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
77 | } else if( ch == '"') { | |
78 | state = SCE_NNCRONTAB_STRING; | |
79 | styler.ColourTo(i,SCE_NNCRONTAB_STRING); | |
80 | } else if( ch == '%') { | |
81 | // signals environment variables | |
82 | state = SCE_NNCRONTAB_ENVIRONMENT; | |
83 | styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); | |
84 | } else if( ch == '*' ) { | |
85 | // signals an asterisk | |
86 | // no state jump necessary for this simple case... | |
87 | styler.ColourTo(i,SCE_NNCRONTAB_ASTERISK); | |
88 | } else if( isalpha(ch) || ch == '<' ) { | |
89 | // signals the start of an identifier | |
90 | bufferCount = 0; | |
91 | buffer[bufferCount++] = ch; | |
92 | state = SCE_NNCRONTAB_IDENTIFIER; | |
93 | } else if( isdigit(ch) ) { | |
94 | // signals the start of a number | |
95 | bufferCount = 0; | |
96 | buffer[bufferCount++] = ch; | |
97 | state = SCE_NNCRONTAB_NUMBER; | |
98 | } else { | |
99 | // style it the default style.. | |
100 | styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); | |
101 | } | |
102 | break; | |
103 | ||
104 | case SCE_NNCRONTAB_COMMENT: | |
105 | // if we find a newline here, | |
106 | // we simply go to default state | |
107 | // else continue to work on it... | |
108 | if( ch == '\n' || ch == '\r' ) { | |
109 | state = SCE_NNCRONTAB_DEFAULT; | |
110 | } else { | |
111 | styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); | |
112 | } | |
113 | break; | |
114 | ||
115 | case SCE_NNCRONTAB_TASK: | |
116 | // if we find a newline here, | |
117 | // we simply go to default state | |
118 | // else continue to work on it... | |
119 | if( ch == '\n' || ch == '\r' ) { | |
120 | state = SCE_NNCRONTAB_DEFAULT; | |
121 | } else { | |
122 | styler.ColourTo(i,SCE_NNCRONTAB_TASK); | |
123 | } | |
124 | break; | |
125 | ||
126 | case SCE_NNCRONTAB_STRING: | |
127 | if( ch == '%' ) { | |
128 | state = SCE_NNCRONTAB_ENVIRONMENT; | |
129 | insideString = true; | |
130 | styler.ColourTo(i-1,SCE_NNCRONTAB_STRING); | |
131 | break; | |
132 | } | |
133 | // if we find the end of a string char, we simply go to default state | |
134 | // else we're still dealing with an string... | |
135 | if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || | |
136 | (ch == '\n') || (ch == '\r') ) { | |
137 | state = SCE_NNCRONTAB_DEFAULT; | |
138 | } | |
139 | styler.ColourTo(i,SCE_NNCRONTAB_STRING); | |
140 | break; | |
141 | ||
142 | case SCE_NNCRONTAB_ENVIRONMENT: | |
143 | // if we find the end of a string char, we simply go to default state | |
144 | // else we're still dealing with an string... | |
145 | if( ch == '%' && insideString ) { | |
146 | state = SCE_NNCRONTAB_STRING; | |
147 | insideString = false; | |
148 | break; | |
149 | } | |
150 | if( (ch == '%' && styler.SafeGetCharAt(i-1)!='\\') | |
151 | || (ch == '\n') || (ch == '\r') ) { | |
152 | state = SCE_NNCRONTAB_DEFAULT; | |
153 | styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); | |
154 | break; | |
155 | } | |
156 | styler.ColourTo(i+1,SCE_NNCRONTAB_ENVIRONMENT); | |
157 | break; | |
158 | ||
159 | case SCE_NNCRONTAB_IDENTIFIER: | |
160 | // stay in CONF_IDENTIFIER state until we find a non-alphanumeric | |
161 | if( isalnum(ch) || (ch == '_') || (ch == '-') || (ch == '/') || | |
162 | (ch == '$') || (ch == '.') || (ch == '<') || (ch == '>') ) { | |
163 | buffer[bufferCount++] = ch; | |
164 | } else { | |
165 | state = SCE_NNCRONTAB_DEFAULT; | |
166 | buffer[bufferCount] = '\0'; | |
167 | ||
168 | // check if the buffer contains a keyword, | |
169 | // and highlight it if it is a keyword... | |
170 | if(section.InList(buffer)) { | |
171 | styler.ColourTo(i,SCE_NNCRONTAB_SECTION ); | |
172 | } else if(keyword.InList(buffer)) { | |
173 | styler.ColourTo(i-1,SCE_NNCRONTAB_KEYWORD ); | |
174 | } // else if(strchr(buffer,'/') || strchr(buffer,'.')) { | |
175 | // styler.ColourTo(i-1,SCE_NNCRONTAB_EXTENSION); | |
176 | // } | |
177 | else if(modifier.InList(buffer)) { | |
178 | styler.ColourTo(i-1,SCE_NNCRONTAB_MODIFIER ); | |
179 | } else { | |
180 | styler.ColourTo(i-1,SCE_NNCRONTAB_DEFAULT); | |
181 | } | |
182 | // push back the faulty character | |
183 | chNext = styler[i--]; | |
184 | } | |
185 | break; | |
186 | ||
187 | case SCE_NNCRONTAB_NUMBER: | |
188 | // stay in CONF_NUMBER state until we find a non-numeric | |
189 | if( isdigit(ch) /* || ch == '.' */ ) { | |
190 | buffer[bufferCount++] = ch; | |
191 | } else { | |
192 | state = SCE_NNCRONTAB_DEFAULT; | |
193 | buffer[bufferCount] = '\0'; | |
194 | // Colourize here... (normal number) | |
195 | styler.ColourTo(i-1,SCE_NNCRONTAB_NUMBER); | |
196 | // push back a character | |
197 | chNext = styler[i--]; | |
198 | } | |
199 | break; | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | LexerModule lmNncrontab(SCLEX_NNCRONTAB, ColouriseNncrontabDoc, "nncrontab"); |