1 // Scintilla source code edit control
2 /** @file LexConf.cxx
3 ** Lexer for Apache Configuration Files.
4 **
5 ** First working version contributed by Ahmad Zawawi <ahmad.zawawi@gmail.com> on October 28, 2000.
6 ** i created this lexer because i needed something pretty when dealing
7 ** when Apache Configuration files...
8 **/
9 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
10 // The License.txt file describes the conditions under which this software may be distributed.
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <assert.h>
17 #include <ctype.h>
18
19 #include "ILexer.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 #include "WordList.h"
24 #include "LexAccessor.h"
25 #include "Accessor.h"
26 #include "StyleContext.h"
27 #include "CharacterSet.h"
28 #include "LexerModule.h"
29
30 using namespace Scintilla;
31
ColouriseConfDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * keywordLists[],Accessor & styler)32 static void ColouriseConfDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler)
33 {
34 int state = SCE_CONF_DEFAULT;
35 char chNext = styler[startPos];
36 Sci_Position lengthDoc = startPos + length;
37 // create a buffer large enough to take the largest chunk...
38 char *buffer = new char[length+1];
39 Sci_Position bufferCount = 0;
40
41 // this assumes that we have 2 keyword list in conf.properties
42 WordList &directives = *keywordLists[0];
43 WordList ¶ms = *keywordLists[1];
44
45 // go through all provided text segment
46 // using the hand-written state machine shown below
47 styler.StartAt(startPos);
48 styler.StartSegment(startPos);
49 for (Sci_Position i = startPos; i < lengthDoc; i++) {
50 char ch = chNext;
51 chNext = styler.SafeGetCharAt(i + 1);
52
53 if (styler.IsLeadByte(ch)) {
54 chNext = styler.SafeGetCharAt(i + 2);
55 i++;
56 continue;
57 }
58 switch(state) {
59 case SCE_CONF_DEFAULT:
60 if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
61 // whitespace is simply ignored here...
62 styler.ColourTo(i,SCE_CONF_DEFAULT);
63 break;
64 } else if( ch == '#' ) {
65 // signals the start of a comment...
66 state = SCE_CONF_COMMENT;
67 styler.ColourTo(i,SCE_CONF_COMMENT);
68 } else if( ch == '.' /*|| ch == '/'*/) {
69 // signals the start of a file...
70 state = SCE_CONF_EXTENSION;
71 styler.ColourTo(i,SCE_CONF_EXTENSION);
72 } else if( ch == '"') {
73 state = SCE_CONF_STRING;
74 styler.ColourTo(i,SCE_CONF_STRING);
75 } else if( IsASCII(ch) && ispunct(ch) ) {
76 // signals an operator...
77 // no state jump necessary for this
78 // simple case...
79 styler.ColourTo(i,SCE_CONF_OPERATOR);
80 } else if( IsASCII(ch) && isalpha(ch) ) {
81 // signals the start of an identifier
82 bufferCount = 0;
83 buffer[bufferCount++] = static_cast<char>(tolower(ch));
84 state = SCE_CONF_IDENTIFIER;
85 } else if( IsASCII(ch) && isdigit(ch) ) {
86 // signals the start of a number
87 bufferCount = 0;
88 buffer[bufferCount++] = ch;
89 //styler.ColourTo(i,SCE_CONF_NUMBER);
90 state = SCE_CONF_NUMBER;
91 } else {
92 // style it the default style..
93 styler.ColourTo(i,SCE_CONF_DEFAULT);
94 }
95 break;
96
97 case SCE_CONF_COMMENT:
98 // if we find a newline here,
99 // we simply go to default state
100 // else continue to work on it...
101 if( ch == '\n' || ch == '\r' ) {
102 state = SCE_CONF_DEFAULT;
103 } else {
104 styler.ColourTo(i,SCE_CONF_COMMENT);
105 }
106 break;
107
108 case SCE_CONF_EXTENSION:
109 // if we find a non-alphanumeric char,
110 // we simply go to default state
111 // else we're still dealing with an extension...
112 if( (IsASCII(ch) && isalnum(ch)) || (ch == '_') ||
113 (ch == '-') || (ch == '$') ||
114 (ch == '/') || (ch == '.') || (ch == '*') )
115 {
116 styler.ColourTo(i,SCE_CONF_EXTENSION);
117 } else {
118 state = SCE_CONF_DEFAULT;
119 chNext = styler[i--];
120 }
121 break;
122
123 case SCE_CONF_STRING:
124 // if we find the end of a string char, we simply go to default state
125 // else we're still dealing with an string...
126 if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') ) {
127 state = SCE_CONF_DEFAULT;
128 }
129 styler.ColourTo(i,SCE_CONF_STRING);
130 break;
131
132 case SCE_CONF_IDENTIFIER:
133 // stay in CONF_IDENTIFIER state until we find a non-alphanumeric
134 if( (IsASCII(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) {
135 buffer[bufferCount++] = static_cast<char>(tolower(ch));
136 } else {
137 state = SCE_CONF_DEFAULT;
138 buffer[bufferCount] = '\0';
139
140 // check if the buffer contains a keyword, and highlight it if it is a keyword...
141 if(directives.InList(buffer)) {
142 styler.ColourTo(i-1,SCE_CONF_DIRECTIVE );
143 } else if(params.InList(buffer)) {
144 styler.ColourTo(i-1,SCE_CONF_PARAMETER );
145 } else if(strchr(buffer,'/') || strchr(buffer,'.')) {
146 styler.ColourTo(i-1,SCE_CONF_EXTENSION);
147 } else {
148 styler.ColourTo(i-1,SCE_CONF_DEFAULT);
149 }
150
151 // push back the faulty character
152 chNext = styler[i--];
153
154 }
155 break;
156
157 case SCE_CONF_NUMBER:
158 // stay in CONF_NUMBER state until we find a non-numeric
159 if( (IsASCII(ch) && isdigit(ch)) || ch == '.') {
160 buffer[bufferCount++] = ch;
161 } else {
162 state = SCE_CONF_DEFAULT;
163 buffer[bufferCount] = '\0';
164
165 // Colourize here...
166 if( strchr(buffer,'.') ) {
167 // it is an IP address...
168 styler.ColourTo(i-1,SCE_CONF_IP);
169 } else {
170 // normal number
171 styler.ColourTo(i-1,SCE_CONF_NUMBER);
172 }
173
174 // push back a character
175 chNext = styler[i--];
176 }
177 break;
178
179 }
180 }
181 delete []buffer;
182 }
183
184 static const char * const confWordListDesc[] = {
185 "Directives",
186 "Parameters",
187 0
188 };
189
190 LexerModule lmConf(SCLEX_CONF, ColouriseConfDoc, "conf", 0, confWordListDesc);
191