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 &params = *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