KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > ShellScriptFormatter


1 /*
2  * ShellScriptFormatter.java
3  *
4  * Copyright (C) 1998-2002 Peter Graves
5  * $Id: ShellScriptFormatter.java,v 1.1.1.1 2002/09/24 16:09:11 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 public final class ShellScriptFormatter extends Formatter
25 {
26     private static final int STATE_BACKQUOTE = STATE_LAST + 1;
27     private static final int STATE_EXPANSION = STATE_LAST + 2;
28     private static final int STATE_HERE_DOCUMENT = STATE_LAST + 3;
29     private static final int STATE_ECHO = STATE_LAST + 4;
30
31     private static final int SHELLSCRIPT_FORMAT_TEXT = 0;
32     private static final int SHELLSCRIPT_FORMAT_COMMENT = 2;
33
34     private static final int SHELLSCRIPT_FORMAT_STRING = 4;
35     private static final int SHELLSCRIPT_FORMAT_KEYWORD = 5;
36     private static final int SHELLSCRIPT_FORMAT_FUNCTION = 6;
37     private static final int SHELLSCRIPT_FORMAT_OPERATOR = 7;
38     private static final int SHELLSCRIPT_FORMAT_BRACE = 8;
39     private static final int SHELLSCRIPT_FORMAT_NUMBER = 9;
40
41     private static StringSet keywords;
42
43     private FastStringBuffer sb = new FastStringBuffer();
44     private int tokStart;
45     private String JavaDoc token;
46
47     private String JavaDoc endOfText;
48
49     public ShellScriptFormatter(Buffer buffer)
50     {
51         this.buffer = buffer;
52     }
53
54     private void endToken(int state)
55     {
56         if (sb.length() > 0) {
57             int format = -1;
58             switch (state) {
59                 case STATE_NEUTRAL:
60                     break;
61                 case STATE_QUOTE:
62                 case STATE_SINGLEQUOTE:
63                 case STATE_BACKQUOTE:
64                 case STATE_HERE_DOCUMENT:
65                 case STATE_ECHO:
66                     format = SHELLSCRIPT_FORMAT_STRING;
67                     break;
68                 case STATE_IDENTIFIER:
69                     break;
70                 case STATE_COMMENT:
71                     format = SHELLSCRIPT_FORMAT_COMMENT;
72                     break;
73                 case STATE_OPERATOR:
74                     format = SHELLSCRIPT_FORMAT_OPERATOR;
75                     break;
76                 case STATE_BRACE:
77                     format = SHELLSCRIPT_FORMAT_BRACE;
78                     break;
79                 case STATE_NUMBER:
80                 case STATE_HEXNUMBER:
81                     format = SHELLSCRIPT_FORMAT_NUMBER;
82                     break;
83             }
84             token = sb.toString();
85             addSegment(token, format);
86             tokStart += token.length();
87             sb.setLength(0);
88         }
89     }
90
91     private void parseLine(String JavaDoc text, int state)
92     {
93         if (Editor.tabsAreVisible())
94             text = Utilities.makeTabsVisible(text, buffer.getTabWidth());
95         else
96             text = Utilities.detab(text, buffer.getTabWidth());
97         clearSegmentList();
98         int braceCount = 0;
99         sb.setLength(0);
100         int i = 0;
101         tokStart = 0;
102         if (state == STATE_HERE_DOCUMENT) {
103             if (text.startsWith(endOfText))
104                 state = STATE_NEUTRAL;
105             else {
106                 sb.append(text);
107                 endToken(state);
108                 return;
109             }
110         }
111         int limit = text.length();
112         char c;
113         // Skip whitespace at start of line.
114
while (i < limit) {
115             c = text.charAt(i);
116             if (Character.isWhitespace(c)) {
117                 sb.append(c);
118                 ++i;
119             } else {
120                 endToken(state);
121                 break;
122             }
123         }
124         while (i < limit) {
125             c = text.charAt(i);
126             if (state == STATE_QUOTE) {
127                 if (c == '"') {
128                     sb.append(c);
129                     endToken(state);
130                     state = STATE_NEUTRAL;
131                 } else {
132                     sb.append(c);
133                     if (c == '\\' && i < limit-1) {
134                         // Escape char.
135
sb.append(text.charAt(++i));
136                     }
137                 }
138                 ++i;
139                 continue;
140             }
141             if (state == STATE_SINGLEQUOTE) {
142                 if (c == '\'') {
143                     sb.append(c);
144                     endToken(state);
145                     state = STATE_NEUTRAL;
146                 } else {
147                     sb.append(c);
148                 }
149                 ++i;
150                 continue;
151             }
152             if (state == STATE_BACKQUOTE) {
153                 if (c == '`') {
154                     sb.append(c);
155                     endToken(state);
156                     state = STATE_NEUTRAL;
157                 } else {
158                     sb.append(c);
159                 }
160                 ++i;
161                 continue;
162             }
163             // Reaching here, we're not in a quoted string.
164
if (c == '"') {
165                 endToken(state);
166                 sb.append(c);
167                 state = STATE_QUOTE;
168                 ++i;
169                 continue;
170             }
171             if (c == '\'') {
172                 endToken(state);
173                 sb.append(c);
174                 state = STATE_SINGLEQUOTE;
175                 ++i;
176                 continue;
177             }
178             if (c == '`') {
179                 endToken(state);
180                 sb.append(c);
181                 state = STATE_BACKQUOTE;
182                 ++i;
183                 continue;
184             }
185             if (state == STATE_ECHO) {
186                 if (c == '\\' && i < limit-1) {
187                     // Escape.
188
sb.append(c);
189                     ++i;
190                     sb.append(text.charAt(i));
191                     ++i;
192                     continue;
193                 }
194                 // Look for terminating ';'.
195
if (c == ';') {
196                     endToken(state);
197                     sb.append(c);
198                     state = STATE_NEUTRAL;
199                 } else
200                     sb.append(c);
201                 ++i;
202                 continue;
203             }
204             if (state == STATE_EXPANSION) {
205                 if (c == '{') {
206                     ++braceCount;
207                     sb.append(c);
208                     ++i;
209                     continue;
210                 }
211                 if (c == '}') {
212                     --braceCount;
213                     if (braceCount == 0) {
214                         sb.append(c) ;
215                         endToken(state);
216                         state = STATE_NEUTRAL;
217                         ++i;
218                         continue;
219                     } else {
220                         sb.append(c);
221                         ++i;
222                         continue;
223                     }
224                 }
225                 if (braceCount == 0) {
226                     if (!buffer.mode.isIdentifierPart(c)) {
227                         endToken(state);
228                         sb.append(c) ;
229                         state = STATE_NEUTRAL;
230                         ++i;
231                         continue;
232                     }
233                 }
234                 sb.append(c);
235                 ++i;
236                 continue;
237             }
238             if (c == '$') {
239                 endToken(state);
240                 sb.append(c);
241                 state = STATE_EXPANSION;
242                 ++i;
243                 continue;
244             }
245             if (c == '#') {
246                 endToken(state);
247                 state = STATE_COMMENT;
248                 sb.append(text.substring(i));
249                 endToken(state);
250                 return;
251             }
252             if (state == STATE_IDENTIFIER) {
253                 if (buffer.mode.isIdentifierPart(c))
254                     sb.append(c);
255                 else {
256                     endToken(state);
257                     if (token.equals("echo"))
258                         state = STATE_ECHO;
259                     else
260                         state = STATE_NEUTRAL;
261                     sb.append(c);
262                 }
263                 ++i;
264                 continue;
265             }
266             if (state == STATE_NUMBER) {
267                 if (Character.isDigit(c))
268                     sb.append(c);
269                 else {
270                     endToken(state);
271                     sb.append(c);
272                     if (buffer.mode.isIdentifierStart(c))
273                         state = STATE_IDENTIFIER;
274                     else
275                         state = STATE_NEUTRAL;
276                 }
277                 ++i;
278                 continue;
279             }
280             if (state == STATE_NEUTRAL) {
281                 if (buffer.mode.isIdentifierStart(c)) {
282                     endToken(state);
283                     sb.append(c);
284                     state = STATE_IDENTIFIER;
285                 } else if (Character.isDigit(c)) {
286                     endToken(state);
287                     sb.append(c);
288                     state = STATE_NUMBER;
289                 } else // Still neutral...
290
sb.append(c);
291             }
292             ++i;
293         }
294         endToken(state);
295     }
296
297     public LineSegmentList formatLine(Line line)
298     {
299         if (line == null) {
300             clearSegmentList();
301             addSegment("", SHELLSCRIPT_FORMAT_TEXT);
302             return segmentList;
303         }
304         parseLine(line.getText(), line.flags());
305         for (int i = 0; i < segmentList.size(); i++) {
306             LineSegment segment = segmentList.getSegment(i);
307             if (segment.getFormat() > 0)
308                 continue;
309             String JavaDoc s = segment.getText();
310             if (isKeyword(s))
311                 segment.setFormat(SHELLSCRIPT_FORMAT_KEYWORD);
312             else
313                 segment.setFormat(SHELLSCRIPT_FORMAT_TEXT);
314         }
315         return segmentList;
316     }
317
318     public boolean parseBuffer()
319     {
320         int state = STATE_NEUTRAL;
321         Line line = buffer.getFirstLine();
322         boolean changed = false;
323         char quoteChar = '\0';
324         while (line != null) {
325             int oldflags = line.flags();
326             if (state == STATE_HERE_DOCUMENT) {
327                 if (line.getText().equals(endOfText))
328                     state = STATE_NEUTRAL;
329             }
330             if (state != oldflags) {
331                 line.setFlags(state);
332                 changed = true;
333             }
334             if (state == STATE_HERE_DOCUMENT) {
335                 line = line.next();
336                 continue;
337             }
338             final int limit = line.length();
339             for (int i = 0; i < limit; i++) {
340                 char c = line.charAt(i);
341                 if (c == '\\' && i < limit - 1) {
342                     // Escape.
343
++i;
344                     continue;
345                 }
346                 if (state == STATE_QUOTE) {
347                     if (c == '"')
348                         state = STATE_NEUTRAL;
349                     continue;
350                 }
351                 if (state == STATE_SINGLEQUOTE) {
352                     if (c == '\'')
353                         state = STATE_NEUTRAL;
354                     continue;
355                 }
356                 // Not in comment or quoted string.
357
if (c == '<' && i < limit-2) {
358                     if (line.charAt(i + 1) == '<') {
359                         endOfText = line.substring(i + 2).trim();
360                         if (endOfText.startsWith("-"))
361                             endOfText = endOfText.substring(1);
362                         int length = endOfText.length();
363                         if (length > 2) {
364                             if (endOfText.charAt(0) == '"' &&
365                                 endOfText.charAt(length - 1) == '"') {
366                                 // Removed enclosing double quotes.
367
endOfText = endOfText.substring(1, length-1);
368                             } else if (endOfText.charAt(0) == '\'' &&
369                                 endOfText.charAt(length - 1) == '\'') {
370                                 // Removed enclosing single quotes.
371
endOfText = endOfText.substring(1, length-1);
372                             }
373                         }
374                         if (endOfText.length() > 0) {
375                             // Make sure "<<" is not shift operator.
376
if (Character.isLetter(endOfText.charAt(0))) {
377                                 state = STATE_HERE_DOCUMENT;
378                                 break;
379                             }
380                         }
381                     }
382                     continue;
383                 }
384                 if (c == '#') {
385                     // BUG!! Could be inside ${ ... }
386
// Single-line comment beginning.
387
// Ignore rest of line.
388
break;
389                 }
390                 if (c == '"')
391                     state = STATE_QUOTE;
392                 else if (c == '\'')
393                     state = STATE_SINGLEQUOTE;
394             }
395             line = line.next();
396         }
397         buffer.setNeedsParsing(false);
398         return changed;
399     }
400
401     public FormatTable getFormatTable()
402     {
403         if (formatTable == null) {
404             formatTable = new FormatTable("ShellScriptMode");
405             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_TEXT, "text");
406             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_COMMENT, "comment");
407             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_STRING, "string");
408             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_KEYWORD, "keyword");
409             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_FUNCTION, "function");
410             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_OPERATOR, "operator");
411             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_BRACE, "brace");
412             formatTable.addEntryFromPrefs(SHELLSCRIPT_FORMAT_NUMBER, "number");
413         }
414         return formatTable;
415     }
416 }
417
Popular Tags