View Javadoc

1   /*
2    * ShellScriptTokenMarker.java - Shell script token marker
3    * Copyright (C) 1998, 1999 Slava Pestov
4    *
5    * You may use and modify this package for any purpose. Redistribution is
6    * permitted, in both source and binary form, provided that this notice
7    * remains intact in all source distributions of this package.
8    */
9   
10  package org.syntax.jedit.tokenmarker;
11  
12  import javax.swing.text.Segment;
13  
14  import org.syntax.jedit.SyntaxUtilities;
15  
16  /***
17   * Shell script token marker.
18   *
19   * @author Slava Pestov
20   * @version $Id: ShellScriptTokenMarker.java,v 1.18 1999/12/13 03:40:30 sp Exp $
21   */
22  public class ShellScriptTokenMarker extends TokenMarker
23  {
24  	// public members
25  	public static final byte LVARIABLE = Token.INTERNAL_FIRST;
26  
27  	public byte markTokensImpl(byte token, Segment line, int lineIndex)
28  	{
29  		char[] array = line.array;
30  		byte cmdState = 0; // 0 = space before command, 1 = inside
31  				// command, 2 = after command
32  		int offset = line.offset;
33  		int lastOffset = offset;
34  		int length = line.count + offset;
35  
36  		if(token == Token.LITERAL1 && lineIndex != 0
37  			&& lineInfo[lineIndex - 1].obj != null)
38  		{
39  			String str = (String)lineInfo[lineIndex - 1].obj;
40  			if(str != null && str.length() == line.count
41  				&& SyntaxUtilities.regionMatches(false,line,
42  				offset,str))
43  			{
44  				addToken(line.count,Token.LITERAL1);
45  				return Token.NULL;
46  			}
47  			else
48  			{
49  				addToken(line.count,Token.LITERAL1);
50  				lineInfo[lineIndex].obj = str;
51  				return Token.LITERAL1;
52  			}
53  		}
54  
55  		boolean backslash = false;
56  loop:		for(int i = offset; i < length; i++)
57  		{
58  			int i1 = (i+1);
59  
60  			char c = array[i];
61  
62  			if(c == '//')
63  			{
64  				backslash = !backslash;
65  				continue;
66  			}
67  
68  			switch(token)
69  			{
70  			case Token.NULL:
71  				switch(c)
72  				{
73  				case ' ': case '\t': case '(': case ')':
74  					backslash = false;
75  					if(cmdState == 1/*insideCmd*/)
76  					{
77  						addToken(i - lastOffset,Token.KEYWORD1);
78  						lastOffset = i;
79  						cmdState = 2; /*afterCmd*/
80  					}
81  					break;
82  				case '=':
83  					backslash = false;
84  					if(cmdState == 1/*insideCmd*/)
85  					{
86  						addToken(i - lastOffset,token);
87  						lastOffset = i;
88  						cmdState = 2; /*afterCmd*/
89  					}
90  					break;
91  				case '&': case '|': case ';':
92  					if(backslash)
93  						backslash = false;
94  					else
95  						cmdState = 0; /*beforeCmd*/
96  					break;
97  				case '#':
98  					if(backslash)
99  						backslash = false;
100 					else
101 					{
102 						addToken(i - lastOffset,token);
103 						addToken(length - i,Token.COMMENT1);
104 						lastOffset = length;
105 						break loop;
106 					}
107 					break;
108 				case '$':
109 					if(backslash)
110 						backslash = false;
111 					else
112 					{
113 						addToken(i - lastOffset,token);
114 						cmdState = 2; /*afterCmd*/
115 						lastOffset = i;
116 						if(length - i >= 2)
117 						{
118 							switch(array[i1])
119 							{
120 							case '(':
121 								continue;
122 							case '{':
123 								token = LVARIABLE;
124 								break;
125 							default:
126 								token = Token.KEYWORD2;
127 								break;
128 							}
129 						}
130 						else
131 							token = Token.KEYWORD2;
132 					}
133 					break;
134 				case '"':
135 					if(backslash)
136 						backslash = false;
137 					else
138 					{
139 						addToken(i - lastOffset,token);
140 						token = Token.LITERAL1;
141 						lineInfo[lineIndex].obj = null;
142 						cmdState = 2; /*afterCmd*/
143 						lastOffset = i;
144 					}
145 					break;
146 				case '\'':
147 					if(backslash)
148 						backslash = false;
149 					else
150 					{
151 						addToken(i - lastOffset,token);
152 						token = Token.LITERAL2;
153 						cmdState = 2; /*afterCmd*/
154 						lastOffset = i;
155 					}
156 					break;
157 				case '<':
158 					if(backslash)
159 						backslash = false;
160 					else
161 					{
162 						if(length - i > 1 && array[i1] == '<')
163 						{
164 							addToken(i - lastOffset,
165 								token);
166 							token = Token.LITERAL1;
167 							lastOffset = i;
168 							lineInfo[lineIndex].obj =
169 								new String(array,i + 2,
170 									length - (i+2));
171 						}
172 					}
173 					break;
174 				default:
175 					backslash = false;
176 					if(Character.isLetter(c))
177 					{
178 						if(cmdState == 0 /*beforeCmd*/)
179 						{
180 							addToken(i - lastOffset,token);
181 							lastOffset = i;
182 							cmdState++; /*insideCmd*/
183 						}
184 					}
185 					break;
186 				}
187 				break;
188 			case Token.KEYWORD2:
189 				backslash = false;
190 				if(!Character.isLetterOrDigit(c) && c != '_')
191 				{
192 					if(i != offset && array[i-1] == '$')
193 					{
194 						addToken(i1 - lastOffset,token);
195 						lastOffset = i1;
196 						token = Token.NULL;
197 						continue;
198 					}
199 					else
200 					{
201 						addToken(i - lastOffset,token);
202 						lastOffset = i;
203 						token = Token.NULL;
204 					}
205 				}
206 				break;
207 			case Token.LITERAL1:
208 				if(backslash)
209 					backslash = false;
210 				else if(c == '"')
211 				{
212 					addToken(i1 - lastOffset,token);
213 					cmdState = 2; /*afterCmd*/
214 					lastOffset = i1;
215 					token = Token.NULL;
216 				}
217 				else
218 					backslash = false;
219 				break;
220 			case Token.LITERAL2:
221 				if(backslash)
222 					backslash = false;
223 				else if(c == '\'')
224 				{
225 					addToken(i1 - lastOffset,Token.LITERAL1);
226 					cmdState = 2; /*afterCmd*/
227 					lastOffset = i1;
228 					token = Token.NULL;
229 				}
230 				else
231 					backslash = false;
232 				break;
233 			case LVARIABLE:
234 				backslash = false;
235 				if(c == '}')
236 				{
237 					addToken(i1 - lastOffset,Token.KEYWORD2);
238 					lastOffset = i1;
239 					token = Token.NULL;
240 				}
241 				break;
242 			default:
243 				throw new InternalError("Invalid state: " + token);
244 			}
245 		}
246 
247 		switch(token)
248 		{
249 		case Token.NULL:
250 			if(cmdState == 1)
251 				addToken(length - lastOffset,Token.KEYWORD1);
252 			else
253 				addToken(length - lastOffset,token);
254 			break;
255 		case Token.LITERAL2:
256 			addToken(length - lastOffset,Token.LITERAL1);
257 			break;
258 		case Token.KEYWORD2:
259 			addToken(length - lastOffset,token);
260 			token = Token.NULL;
261 			break;
262 		case LVARIABLE:
263 			addToken(length - lastOffset,Token.INVALID);
264 			token = Token.NULL;
265 			break;
266 		default:
267 			addToken(length - lastOffset,token);
268 			break;
269 		}
270 		return token;
271 	}
272 }