1 // Scintilla source code edit control
2 /** @file LexAsn1.cxx
3  ** Lexer for ASN.1
4  **/
5 // Copyright 2004 by Herr Pfarrer rpfarrer <at> yahoo <dot> de
6 // Last Updated: 20/07/2004
7 // The License.txt file describes the conditions under which this software may be distributed.
8 
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 
15 #include "ILexer.h"
16 #include "Scintilla.h"
17 #include "SciLexer.h"
18 
19 #include "WordList.h"
20 #include "LexAccessor.h"
21 #include "Accessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
25 
26 #ifdef SCI_NAMESPACE
27 using namespace Scintilla;
28 #endif
29 
30 // Some char test functions
isAsn1Number(int ch)31 static bool isAsn1Number(int ch)
32 {
33 	return (ch >= '0' && ch <= '9');
34 }
35 
isAsn1Letter(int ch)36 static bool isAsn1Letter(int ch)
37 {
38 	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
39 }
40 
isAsn1Char(int ch)41 static bool isAsn1Char(int ch)
42 {
43 	return (ch == '-' ) || isAsn1Number(ch) || isAsn1Letter (ch);
44 }
45 
46 //
47 //	Function determining the color of a given code portion
48 //	Based on a "state"
49 //
ColouriseAsn1Doc(unsigned int startPos,int length,int initStyle,WordList * keywordLists[],Accessor & styler)50 static void ColouriseAsn1Doc(unsigned int startPos, int length, int initStyle, WordList *keywordLists[], Accessor &styler)
51 {
52 	// The keywords
53 	WordList &Keywords = *keywordLists[0];
54 	WordList &Attributes = *keywordLists[1];
55 	WordList &Descriptors = *keywordLists[2];
56 	WordList &Types = *keywordLists[3];
57 
58 	// Parse the whole buffer character by character using StyleContext
59 	StyleContext sc(startPos, length, initStyle, styler);
60 	for (; sc.More(); sc.Forward())
61 	{
62 		// The state engine
63 		switch (sc.state)
64 		{
65 		case SCE_ASN1_DEFAULT:		// Plain characters
66 asn1_default:
67 			if (sc.ch == '-' && sc.chNext == '-')
68 				// A comment begins here
69 				sc.SetState(SCE_ASN1_COMMENT);
70 			else if (sc.ch == '"')
71 				// A string begins here
72 				sc.SetState(SCE_ASN1_STRING);
73 			else if (isAsn1Number (sc.ch))
74 				// A number starts here (identifier should start with a letter in ASN.1)
75 				sc.SetState(SCE_ASN1_SCALAR);
76 			else if (isAsn1Char (sc.ch))
77 				// An identifier starts here (identifier always start with a letter)
78 				sc.SetState(SCE_ASN1_IDENTIFIER);
79 			else if (sc.ch == ':')
80 				// A ::= operator starts here
81 				sc.SetState(SCE_ASN1_OPERATOR);
82 			break;
83 		case SCE_ASN1_COMMENT:		// A comment
84 			if (sc.ch == '\r' || sc.ch == '\n')
85 				// A comment ends here
86 				sc.SetState(SCE_ASN1_DEFAULT);
87 			break;
88 		case SCE_ASN1_IDENTIFIER:	// An identifier (keyword, attribute, descriptor or type)
89 			if (!isAsn1Char (sc.ch))
90 			{
91 				// The end of identifier is here: we can look for it in lists by now and change its state
92 				char s[100];
93 				sc.GetCurrent(s, sizeof(s));
94 				if (Keywords.InList(s))
95 					// It's a keyword, change its state
96 					sc.ChangeState(SCE_ASN1_KEYWORD);
97 				else if (Attributes.InList(s))
98 					// It's an attribute, change its state
99 					sc.ChangeState(SCE_ASN1_ATTRIBUTE);
100 				else if (Descriptors.InList(s))
101 					// It's a descriptor, change its state
102 					sc.ChangeState(SCE_ASN1_DESCRIPTOR);
103 				else if (Types.InList(s))
104 					// It's a type, change its state
105 					sc.ChangeState(SCE_ASN1_TYPE);
106 
107 				// Set to default now
108 				sc.SetState(SCE_ASN1_DEFAULT);
109 			}
110 			break;
111 		case SCE_ASN1_STRING:		// A string delimited by ""
112 			if (sc.ch == '"')
113 			{
114 				// A string ends here
115 				sc.ForwardSetState(SCE_ASN1_DEFAULT);
116 
117 				// To correctly manage a char sticking to the string quote
118 				goto asn1_default;
119 			}
120 			break;
121 		case SCE_ASN1_SCALAR:		// A plain number
122 			if (!isAsn1Number (sc.ch))
123 				// A number ends here
124 				sc.SetState(SCE_ASN1_DEFAULT);
125 			break;
126 		case SCE_ASN1_OPERATOR:		// The affectation operator ::= and wath follows (eg: ::= { org 6 } OID or ::= 12 trap)
127 			if (sc.ch == '{')
128 			{
129 				// An OID definition starts here: enter the sub loop
130 				for (; sc.More(); sc.Forward())
131 				{
132 					if (isAsn1Number (sc.ch) && (!isAsn1Char (sc.chPrev) || isAsn1Number (sc.chPrev)))
133 						// The OID number is highlighted
134 						sc.SetState(SCE_ASN1_OID);
135 					else if (isAsn1Char (sc.ch))
136 						// The OID parent identifier is plain
137 						sc.SetState(SCE_ASN1_IDENTIFIER);
138 					else
139 						sc.SetState(SCE_ASN1_DEFAULT);
140 
141 					if (sc.ch == '}')
142 						// Here ends the OID and the operator sub loop: go back to main loop
143 						break;
144 				}
145 			}
146 			else if (isAsn1Number (sc.ch))
147 			{
148 				// A trap number definition starts here: enter the sub loop
149 				for (; sc.More(); sc.Forward())
150 				{
151 					if (isAsn1Number (sc.ch))
152 						// The trap number is highlighted
153 						sc.SetState(SCE_ASN1_OID);
154 					else
155 					{
156 						// The number ends here: go back to main loop
157 						sc.SetState(SCE_ASN1_DEFAULT);
158 						break;
159 					}
160 				}
161 			}
162 			else if (sc.ch != ':' && sc.ch != '=' && sc.ch != ' ')
163 				// The operator doesn't imply an OID definition nor a trap, back to main loop
164 				goto asn1_default; // To be sure to handle actually the state change
165 			break;
166 		}
167 	}
168 	sc.Complete();
169 }
170 
FoldAsn1Doc(unsigned int,int,int,WordList * [],Accessor & styler)171 static void FoldAsn1Doc(unsigned int, int, int, WordList *[], Accessor &styler)
172 {
173 	// No folding enabled, no reason to continue...
174 	if( styler.GetPropertyInt("fold") == 0 )
175 		return;
176 
177 	// No folding implemented: doesn't make sense for ASN.1
178 }
179 
180 static const char * const asn1WordLists[] = {
181 	"Keywords",
182 	"Attributes",
183 	"Descriptors",
184 	"Types",
185 	0, };
186 
187 
188 LexerModule lmAsn1(SCLEX_ASN1, ColouriseAsn1Doc, "asn1", FoldAsn1Doc, asn1WordLists);
189