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