001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * ShellScriptTokenMarker.java
028: *
029: */
030:
031: package org.syntax.jedit.tokenmarker;
032:
033: import org.syntax.jedit.*;
034: import javax.swing.text.Segment;
035:
036: /**
037: * Shell script token marker.
038: *
039: * @author Slava Pestov
040: * @version $Id: ShellScriptTokenMarker.java 1167 2008-01-15 18:49:05Z gtoffoli $
041: */
042: public class ShellScriptTokenMarker extends TokenMarker {
043: // public members
044: public static final byte LVARIABLE = Token.INTERNAL_FIRST;
045:
046: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
047: char[] array = line.array;
048: byte cmdState = 0; // 0 = space before command, 1 = inside
049: // command, 2 = after command
050: int offset = line.offset;
051: int lastOffset = offset;
052: int length = line.count + offset;
053:
054: if (token == Token.LITERAL1 && lineIndex != 0
055: && lineInfo[lineIndex - 1].obj != null) {
056: String str = (String) lineInfo[lineIndex - 1].obj;
057: if (str != null
058: && str.length() == line.count
059: && SyntaxUtilities.regionMatches(false, line,
060: offset, str)) {
061: addToken(line.count, Token.LITERAL1);
062: return Token.NULL;
063: } else {
064: addToken(line.count, Token.LITERAL1);
065: lineInfo[lineIndex].obj = str;
066: return Token.LITERAL1;
067: }
068: }
069:
070: boolean backslash = false;
071: loop: for (int i = offset; i < length; i++) {
072: int i1 = (i + 1);
073:
074: char c = array[i];
075:
076: if (c == '\\') {
077: backslash = !backslash;
078: continue;
079: }
080:
081: switch (token) {
082: case Token.NULL:
083: switch (c) {
084: case ' ':
085: case '\t':
086: case '(':
087: case ')':
088: backslash = false;
089: if (cmdState == 1/*insideCmd*/) {
090: addToken(i - lastOffset, Token.KEYWORD1);
091: lastOffset = i;
092: cmdState = 2; /*afterCmd*/
093: }
094: break;
095: case '=':
096: backslash = false;
097: if (cmdState == 1/*insideCmd*/) {
098: addToken(i - lastOffset, token);
099: lastOffset = i;
100: cmdState = 2; /*afterCmd*/
101: }
102: break;
103: case '&':
104: case '|':
105: case ';':
106: if (backslash)
107: backslash = false;
108: else
109: cmdState = 0; /*beforeCmd*/
110: break;
111: case '#':
112: if (backslash)
113: backslash = false;
114: else {
115: addToken(i - lastOffset, token);
116: addToken(length - i, Token.COMMENT1);
117: lastOffset = length;
118: break loop;
119: }
120: break;
121: case '$':
122: if (backslash)
123: backslash = false;
124: else {
125: addToken(i - lastOffset, token);
126: cmdState = 2; /*afterCmd*/
127: lastOffset = i;
128: if (length - i >= 2) {
129: switch (array[i1]) {
130: case '(':
131: continue;
132: case '{':
133: token = LVARIABLE;
134: break;
135: default:
136: token = Token.KEYWORD2;
137: break;
138: }
139: } else
140: token = Token.KEYWORD2;
141: }
142: break;
143: case '"':
144: if (backslash)
145: backslash = false;
146: else {
147: addToken(i - lastOffset, token);
148: token = Token.LITERAL1;
149: lineInfo[lineIndex].obj = null;
150: cmdState = 2; /*afterCmd*/
151: lastOffset = i;
152: }
153: break;
154: case '\'':
155: if (backslash)
156: backslash = false;
157: else {
158: addToken(i - lastOffset, token);
159: token = Token.LITERAL2;
160: cmdState = 2; /*afterCmd*/
161: lastOffset = i;
162: }
163: break;
164: case '<':
165: if (backslash)
166: backslash = false;
167: else {
168: if (length - i > 1 && array[i1] == '<') {
169: addToken(i - lastOffset, token);
170: token = Token.LITERAL1;
171: lastOffset = i;
172: lineInfo[lineIndex].obj = new String(array,
173: i + 2, length - (i + 2));
174: }
175: }
176: break;
177: default:
178: backslash = false;
179: if (Character.isLetter(c)) {
180: if (cmdState == 0 /*beforeCmd*/) {
181: addToken(i - lastOffset, token);
182: lastOffset = i;
183: cmdState++; /*insideCmd*/
184: }
185: }
186: break;
187: }
188: break;
189: case Token.KEYWORD2:
190: backslash = false;
191: if (!Character.isLetterOrDigit(c) && c != '_') {
192: if (i != offset && array[i - 1] == '$') {
193: addToken(i1 - lastOffset, token);
194: lastOffset = i1;
195: token = Token.NULL;
196: continue;
197: } else {
198: addToken(i - lastOffset, token);
199: lastOffset = i;
200: token = Token.NULL;
201: }
202: }
203: break;
204: case Token.LITERAL1:
205: if (backslash)
206: backslash = false;
207: else if (c == '"') {
208: addToken(i1 - lastOffset, token);
209: cmdState = 2; /*afterCmd*/
210: lastOffset = i1;
211: token = Token.NULL;
212: } else
213: backslash = false;
214: break;
215: case Token.LITERAL2:
216: if (backslash)
217: backslash = false;
218: else if (c == '\'') {
219: addToken(i1 - lastOffset, Token.LITERAL1);
220: cmdState = 2; /*afterCmd*/
221: lastOffset = i1;
222: token = Token.NULL;
223: } else
224: backslash = false;
225: break;
226: case LVARIABLE:
227: backslash = false;
228: if (c == '}') {
229: addToken(i1 - lastOffset, Token.KEYWORD2);
230: lastOffset = i1;
231: token = Token.NULL;
232: }
233: break;
234: default:
235: throw new InternalError("Invalid state: " + token);
236: }
237: }
238:
239: switch (token) {
240: case Token.NULL:
241: if (cmdState == 1)
242: addToken(length - lastOffset, Token.KEYWORD1);
243: else
244: addToken(length - lastOffset, token);
245: break;
246: case Token.LITERAL2:
247: addToken(length - lastOffset, Token.LITERAL1);
248: break;
249: case Token.KEYWORD2:
250: addToken(length - lastOffset, token);
251: token = Token.NULL;
252: break;
253: case LVARIABLE:
254: addToken(length - lastOffset, Token.INVALID);
255: token = Token.NULL;
256: break;
257: default:
258: addToken(length - lastOffset, token);
259: break;
260: }
261: return token;
262: }
263: }
|