KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bsf > util > cf > CodeFormatter


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2002 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if
20  * any, must include the following acknowlegement:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowlegement may appear in the software itself,
24  * if and wherever such third-party acknowlegements normally appear.
25  *
26  * 4. The names "Apache BSF", "Apache", and "Apache Software Foundation"
27  * must not be used to endorse or promote products derived from
28  * this software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache"
32  * nor may "Apache" appear in their names without prior written
33  * permission of the Apache Group.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many individuals
50  * on behalf of the Apache Software Foundation and was originally created by
51  * Sanjiva Weerawarana and others at International Business Machines
52  * Corporation. For more information on the Apache Software Foundation,
53  * please see <http://www.apache.org/>.
54  */

55
56 package org.apache.bsf.util.cf;
57
58 import java.io.*;
59 import java.util.*;
60 import org.apache.bsf.util.*;
61
62 /**
63  * A <code>CodeFormatter</code> bean is used to format raw Java code. It
64  * indents, word-wraps, and replaces tab characters with an amount of space
65  * characters equal to the size of the <code>indentationStep</code> property.
66  * To create and use a <code>CodeFormatter</code>, you simply instantiate a
67  * new <code>CodeFormatter</code> bean, and invoke
68  * <code>formatCode(Reader source, Writer target)</code> with appropriate
69  * arguments.
70  *
71  * @version 1.0
72  * @author Matthew J. Duftler
73  */

74 public class CodeFormatter
75 {
76   /**
77    * The default maximum line length.
78    */

79   public static final int DEFAULT_MAX = 74;
80   /**
81    * The default size of the indentation step.
82    */

83   public static final int DEFAULT_STEP = 2;
84   /**
85    * The default set of delimiters.
86    */

87   public static final String JavaDoc DEFAULT_DELIM = "(+";
88   /**
89    * The default set of sticky delimiters.
90    */

91   public static final String JavaDoc DEFAULT_S_DELIM = ",";
92
93   // Configurable Parameters
94
private int maxLineLength = DEFAULT_MAX;
95   private int indentationStep = DEFAULT_STEP;
96   private String JavaDoc delimiters = DEFAULT_DELIM;
97   private String JavaDoc stickyDelimiters = DEFAULT_S_DELIM;
98
99   // Global Variables
100
private int indent;
101   private int hangingIndent;
102   private int origIndent;
103   private boolean inCPP_Comment;
104
105   private void addTok(StringBuffer JavaDoc targetBuf, StringBuffer JavaDoc tokBuf,
106                       IndentWriter out)
107   {
108     int tokLength = tokBuf.length(),
109         targetLength = targetBuf.length();
110
111     if (indent + targetLength + tokLength > maxLineLength)
112     {
113       if (targetLength == 0)
114       {
115         out.println(indent, tokBuf.toString());
116         indent = hangingIndent;
117         targetBuf.setLength(0);
118
119         return;
120       }
121       else
122       {
123         out.println(indent, targetBuf.toString().trim());
124         indent = hangingIndent;
125         targetBuf.setLength(0);
126       }
127     }
128
129     targetBuf.append(tokBuf.toString());
130
131     return;
132   }
133   /**
134    * Formats the code read from <code>source</code>, and writes the formatted
135    * code to <code>target</code>.
136    *
137    * @param source where to read the unformatted code from.
138    * @param target where to write the formatted code to.
139    */

140   public void formatCode(Reader source, Writer target)
141   {
142     String JavaDoc line;
143     BufferedReader in = new BufferedReader(source);
144     IndentWriter out = new IndentWriter(new BufferedWriter(target), true);
145
146     try
147     {
148       origIndent = 0;
149       inCPP_Comment = false;
150
151       while ((line = in.readLine()) != null)
152       {
153         line = line.trim();
154
155         if (line.length() > 0)
156         {
157           indent = origIndent;
158           hangingIndent = indent + indentationStep;
159           printLine(line, out);
160         }
161         else
162           out.println();
163       }
164     }
165     catch (IOException e)
166     {
167       e.printStackTrace();
168     }
169   }
170   /**
171    * Gets the set of delimiters.
172    *
173    * @return the set of delimiters.
174    * @see #setDelimiters
175    */

176   public String JavaDoc getDelimiters()
177   {
178     return delimiters;
179   }
180   /**
181    * Gets the size of the indentation step.
182    *
183    * @return the size of the indentation step.
184    * @see #setIndentationStep
185    */

186   public int getIndentationStep()
187   {
188     return indentationStep;
189   }
190   /**
191    * Gets the maximum line length.
192    *
193    * @return the maximum line length.
194    * @see #setMaxLineLength
195    */

196   public int getMaxLineLength()
197   {
198     return maxLineLength;
199   }
200   /**
201    * Gets the set of sticky delimiters.
202    *
203    * @return the set of sticky delimiters.
204    * @see #setStickyDelimiters
205    */

206   public String JavaDoc getStickyDelimiters()
207   {
208     return stickyDelimiters;
209   }
210   private void printLine(String JavaDoc line, IndentWriter out)
211   {
212     char[] source = line.toCharArray();
213     char ch;
214     char quoteChar = ' ';
215     boolean inEscapeSequence = false;
216     boolean inString = false;
217     StringBuffer JavaDoc tokBuf = new StringBuffer JavaDoc(),
218                  targetBuf = new StringBuffer JavaDoc(hangingIndent + line.length());
219
220     for (int i = 0; i < source.length; i++)
221     {
222       ch = source[i];
223
224       if (inEscapeSequence)
225       {
226         tokBuf.append(ch);
227         inEscapeSequence = false;
228       }
229       else
230       {
231         if (inString)
232         {
233           switch (ch)
234           {
235             case '\\' :
236               tokBuf.append('\\');
237               inEscapeSequence = true;
238               break;
239             case '\'' :
240             case '\"' :
241               tokBuf.append(ch);
242
243               if (ch == quoteChar)
244               {
245                 addTok(targetBuf, tokBuf, out);
246                 tokBuf.setLength(0);
247                 inString = false;
248               }
249               break;
250             case 9 : // pass thru tab characters...
251
tokBuf.append(ch);
252               break;
253             default :
254               if (ch > 31)
255                 tokBuf.append(ch);
256               break;
257           }
258         }
259         else // !inString
260
{
261           if (inCPP_Comment)
262           {
263             tokBuf.append(ch);
264
265             if (ch == '/' && i > 0 && source[i - 1] == '*')
266               inCPP_Comment = false;
267           }
268           else
269           {
270             switch (ch)
271             {
272               case '/' :
273                 tokBuf.append(ch);
274
275                 if (i > 0 && source[i - 1] == '/')
276                 {
277                   String JavaDoc tokStr = tokBuf.append(source,
278                                                 i + 1,
279                                                 source.length - (i + 1)).toString();
280
281                   out.println(indent, targetBuf.append(tokStr).toString());
282
283                   return;
284                 }
285                 break;
286               case '*' :
287                 tokBuf.append(ch);
288
289                 if (i > 0 && source[i - 1] == '/')
290                   inCPP_Comment = true;
291                 break;
292               case '\'' :
293               case '\"' :
294                 addTok(targetBuf, tokBuf, out);
295                 tokBuf.setLength(0);
296                 tokBuf.append(ch);
297                 quoteChar = ch;
298                 inString = true;
299                 break;
300               case 9 : // replace tab characters...
301
tokBuf.append(StringUtils.getChars(indentationStep, ' '));
302                 break;
303               case '{' :
304                 tokBuf.append(ch);
305                 origIndent += indentationStep;
306                 break;
307               case '}' :
308                 tokBuf.append(ch);
309                 origIndent -= indentationStep;
310
311                 if (i == 0)
312                   indent = origIndent;
313                 break;
314               default :
315                 if (ch > 31)
316                 {
317                   if (delimiters.indexOf(ch) != -1)
318                   {
319                     addTok(targetBuf, tokBuf, out);
320                     tokBuf.setLength(0);
321                     tokBuf.append(ch);
322                   }
323                   else if (stickyDelimiters.indexOf(ch) != -1)
324                   {
325                     tokBuf.append(ch);
326                     addTok(targetBuf, tokBuf, out);
327                     tokBuf.setLength(0);
328                   }
329                   else
330                     tokBuf.append(ch);
331                 }
332                 break;
333             }
334           }
335         }
336       }
337     }
338
339     if (tokBuf.length() > 0)
340       addTok(targetBuf, tokBuf, out);
341
342     String JavaDoc lastLine = targetBuf.toString().trim();
343
344     if (lastLine.length() > 0)
345       out.println(indent, lastLine);
346   }
347   /**
348    * Sets the set of delimiters; default set is <code>"(+"</code>.
349    * <p>
350    * Each character represents one delimiter. If a line is ready to be
351    * word-wrapped and a delimiter is encountered, the delimiter will
352    * appear as the <em>first character on the following line</em>.
353    * A quotation mark, <code>"</code> or <code>'</code>, opening a string
354    * is always a delimiter, whether you specify it or not.
355    *
356    * @param newDelimiters the new set of delimiters.
357    * @see #getDelimiters
358    */

359   public void setDelimiters(String JavaDoc newDelimiters)
360   {
361     delimiters = newDelimiters;
362   }
363   /**
364    * Sets the size of the indentation step; default size is <code>2</code>.
365    * <p>
366    * This is the number of spaces that lines will be indented (when appropriate).
367    *
368    * @param newIndentationStep the new size of the indentation step.
369    * @see #getIndentationStep
370    */

371   public void setIndentationStep(int newIndentationStep)
372   {
373     indentationStep = (newIndentationStep < 0 ? 0 : newIndentationStep);
374   }
375   /**
376    * Sets the (desired) maximum line length; default length is
377    * <code>74</code>.
378    * <p>
379    * If a token is longer than the requested maximum line length,
380    * then the line containing that token will obviously be longer
381    * than the desired maximum.
382    *
383    * @param newMaxLineLength the new maximum line length.
384    * @see #getMaxLineLength
385    */

386   public void setMaxLineLength(int newMaxLineLength)
387   {
388     maxLineLength = (newMaxLineLength < 0 ? 0 : newMaxLineLength);
389   }
390   /**
391    * Sets the set of sticky delimiters; default set is <code>","</code>.
392    * <p>
393    * Each character represents one sticky delimiter. If a line is ready
394    * to be word-wrapped and a sticky delimiter is encountered, the sticky
395    * delimiter will appear as the <em>last character on the current line</em>.
396    * A quotation mark, <code>"</code> or <code>'</code>, closing a string
397    * is always a sticky delimiter, whether you specify it or not.
398    *
399    * @param newStickyDelimiters the new set of sticky delimiters.
400    * @see #getStickyDelimiters
401    */

402   public void setStickyDelimiters(String JavaDoc newStickyDelimiters)
403   {
404     stickyDelimiters = newStickyDelimiters;
405   }
406 }
407
Popular Tags