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