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