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