Save This Page
Home » bsf-src-2.4.0 » org.apache.bsf.util.cf » [javadoc | source]
    1   /*
    2    * Copyright 2004,2004 The Apache Software Foundation.
    3    * 
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    * 
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    * 
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.apache.bsf.util.cf;
   18   
   19   import java.io.BufferedReader;
   20   import java.io.BufferedWriter;
   21   import java.io.IOException;
   22   import java.io.Reader;
   23   import java.io.Writer;
   24   
   25   import org.apache.bsf.util.IndentWriter;
   26   import org.apache.bsf.util.StringUtils;
   27   
   28   /**
   29    * A <code>CodeFormatter</code> bean is used to format raw Java code. It
   30    * indents, word-wraps, and replaces tab characters with an amount of space
   31    * characters equal to the size of the <code>indentationStep</code> property.
   32    * To create and use a <code>CodeFormatter</code>, you simply instantiate a
   33    * new <code>CodeFormatter</code> bean, and invoke
   34    * <code>formatCode(Reader source, Writer target)</code> with appropriate
   35    * arguments.
   36    *
   37    * @version 1.0
   38    * @author Matthew J. Duftler
   39    */
   40   public class CodeFormatter
   41   {
   42     /**
   43      * The default maximum line length.
   44      */
   45     public static final int     DEFAULT_MAX      = 74;
   46     /**
   47      * The default size of the indentation step.
   48      */
   49     public static final int     DEFAULT_STEP     = 2;
   50     /**
   51      * The default set of delimiters.
   52      */
   53     public static final String  DEFAULT_DELIM    = "(+";
   54     /**
   55      * The default set of sticky delimiters.
   56      */
   57     public static final String  DEFAULT_S_DELIM  = ",";
   58   
   59     // Configurable Parameters
   60     private             int     maxLineLength    = DEFAULT_MAX;
   61     private             int     indentationStep  = DEFAULT_STEP;
   62     private             String  delimiters       = DEFAULT_DELIM;
   63     private             String  stickyDelimiters = DEFAULT_S_DELIM;
   64   
   65     // Global Variables
   66     private             int     indent;
   67     private             int     hangingIndent;
   68     private             int     origIndent;
   69     private             boolean inCPP_Comment;
   70   
   71     private void addTok(StringBuffer targetBuf, StringBuffer tokBuf,
   72   					  IndentWriter out)
   73     {
   74   	int tokLength    = tokBuf.length(),
   75   		targetLength = targetBuf.length();
   76   
   77   	if (indent + targetLength + tokLength > maxLineLength)
   78   	{
   79   	  if (targetLength == 0)
   80   	  {
   81   		out.println(indent, tokBuf.toString());
   82   		indent = hangingIndent;
   83   		targetBuf.setLength(0);
   84   
   85   		return;
   86   	  }
   87   	  else
   88   	  {
   89   		out.println(indent, targetBuf.toString().trim());
   90   		indent = hangingIndent;
   91   		targetBuf.setLength(0);
   92   	  }
   93   	}
   94   
   95   	targetBuf.append(tokBuf.toString());
   96   
   97   	return;
   98     }
   99     /**
  100      * Formats the code read from <code>source</code>, and writes the formatted
  101      * code to <code>target</code>.
  102      *
  103      * @param source where to read the unformatted code from.
  104      * @param target where to write the formatted code to.
  105      */
  106     public void formatCode(Reader source, Writer target)
  107     {
  108   	String         line;
  109   	BufferedReader in  = new BufferedReader(source);
  110   	IndentWriter   out = new IndentWriter(new BufferedWriter(target), true);
  111   
  112   	try
  113   	{
  114   	  origIndent    = 0;
  115   	  inCPP_Comment = false;
  116   
  117   	  while ((line = in.readLine()) != null)
  118   	  {
  119   		line = line.trim();
  120   
  121   		if (line.length() > 0)
  122   		{
  123   		  indent        = origIndent;
  124   		  hangingIndent = indent + indentationStep;
  125   		  printLine(line, out);
  126   		}
  127   		else
  128   		  out.println();
  129   	  }
  130   	}
  131   	catch (IOException e)
  132   	{
  133   	  e.printStackTrace();
  134   	}
  135     }
  136     /**
  137      * Gets the set of delimiters.
  138      *
  139      * @return the set of delimiters.
  140      * @see #setDelimiters
  141      */
  142     public String getDelimiters()
  143     {
  144   	return delimiters;
  145     }
  146     /**
  147      * Gets the size of the indentation step.
  148      *
  149      * @return the size of the indentation step.
  150      * @see #setIndentationStep
  151      */
  152     public int getIndentationStep()
  153     {
  154   	return indentationStep;
  155     }
  156     /**
  157      * Gets the maximum line length.
  158      *
  159      * @return the maximum line length.
  160      * @see #setMaxLineLength
  161      */
  162     public int getMaxLineLength()
  163     {
  164   	return maxLineLength;
  165     }
  166     /**
  167      * Gets the set of sticky delimiters.
  168      *
  169      * @return the set of sticky delimiters.
  170      * @see #setStickyDelimiters
  171      */
  172     public String getStickyDelimiters()
  173     {
  174   	return stickyDelimiters;
  175     }
  176     private void printLine(String line, IndentWriter out)
  177     {
  178   	char[]       source           = line.toCharArray();
  179   	char         ch;
  180   	char         quoteChar        = ' ';
  181   	boolean      inEscapeSequence = false;
  182   	boolean      inString         = false;
  183   	StringBuffer tokBuf           = new StringBuffer(),
  184   				 targetBuf        = new StringBuffer(hangingIndent + line.length());
  185   
  186   	for (int i = 0; i < source.length; i++)
  187   	{
  188   	  ch = source[i];
  189   
  190   	  if (inEscapeSequence)
  191   	  {
  192   		tokBuf.append(ch);
  193   		inEscapeSequence = false;
  194   	  }
  195   	  else
  196   	  {
  197   		if (inString)
  198   		{
  199   		  switch (ch)
  200   		  {
  201   			case '\\' :
  202   			  tokBuf.append('\\');
  203   			  inEscapeSequence = true;
  204   			  break;
  205   			case '\'' :
  206   			case '\"' :
  207   			  tokBuf.append(ch);
  208   
  209   			  if (ch == quoteChar)
  210   			  {
  211   				addTok(targetBuf, tokBuf, out);
  212   				tokBuf.setLength(0);
  213   				inString = false;
  214   			  }
  215   			  break;
  216   			case 9 :  // pass thru tab characters...
  217   			  tokBuf.append(ch);
  218   			  break;
  219   			default :
  220   			  if (ch > 31)
  221   				tokBuf.append(ch);
  222   			  break;
  223   		  }
  224   		}
  225   		else  // !inString
  226   		{
  227   		  if (inCPP_Comment)
  228   		  {
  229   			tokBuf.append(ch);
  230   
  231   			if (ch == '/' && i > 0 && source[i - 1] == '*')
  232   			  inCPP_Comment = false;
  233   		  }
  234   		  else
  235   		  {
  236   			switch (ch)
  237   			{
  238   			  case '/' :
  239   				tokBuf.append(ch);
  240   
  241   				if (i > 0 && source[i - 1] == '/')
  242   				{
  243   				  String tokStr = tokBuf.append(source,
  244   												i + 1,
  245   												source.length - (i + 1)).toString();
  246   
  247   				  out.println(indent, targetBuf.append(tokStr).toString());
  248   
  249   				  return;
  250   				}
  251   				break;
  252   			  case '*' :
  253   				tokBuf.append(ch);
  254   
  255   				if (i > 0 && source[i - 1] == '/')
  256   				  inCPP_Comment = true;
  257   				break;
  258   			  case '\'' :
  259   			  case '\"' :
  260   				addTok(targetBuf, tokBuf, out);
  261   				tokBuf.setLength(0);
  262   				tokBuf.append(ch);
  263   				quoteChar = ch;
  264   				inString  = true;
  265   				break;
  266   			  case 9 :  // replace tab characters...
  267   				tokBuf.append(StringUtils.getChars(indentationStep, ' '));
  268   				break;
  269   			  case '{' :
  270   				tokBuf.append(ch);
  271   				origIndent += indentationStep;
  272   				break;
  273   			  case '}' :
  274   				tokBuf.append(ch);
  275   				origIndent -= indentationStep;
  276   
  277   				if (i == 0)
  278   				  indent = origIndent;
  279   				break;
  280   			  default :
  281   				if (ch > 31)
  282   				{
  283   				  if (delimiters.indexOf(ch) != -1)
  284   				  {
  285   					addTok(targetBuf, tokBuf, out);
  286   					tokBuf.setLength(0);
  287   					tokBuf.append(ch);
  288   				  }
  289   				  else if (stickyDelimiters.indexOf(ch) != -1)
  290   				  {
  291   					tokBuf.append(ch);
  292   					addTok(targetBuf, tokBuf, out);
  293   					tokBuf.setLength(0);
  294   				  }
  295   				  else
  296   					tokBuf.append(ch);
  297   				}
  298   				break;
  299   			}
  300   		  }
  301   		}
  302   	  }
  303   	}
  304   
  305   	if (tokBuf.length() > 0)
  306   	  addTok(targetBuf, tokBuf, out);
  307   
  308   	String lastLine = targetBuf.toString().trim();
  309   
  310   	if (lastLine.length() > 0)
  311   	  out.println(indent, lastLine);
  312     }
  313     /**
  314      * Sets the set of delimiters; default set is <code>"(+"</code>.
  315      * <p>
  316      * Each character represents one delimiter. If a line is ready to be
  317      * word-wrapped and a delimiter is encountered, the delimiter will
  318      * appear as the <em>first character on the following line</em>.
  319      * A quotation mark, <code>"</code> or <code>'</code>, opening a string
  320      * is always a delimiter, whether you specify it or not.
  321      *
  322      * @param newDelimiters the new set of delimiters.
  323      * @see #getDelimiters
  324      */
  325     public void setDelimiters(String newDelimiters)
  326     {
  327   	delimiters = newDelimiters;
  328     }
  329     /**
  330      * Sets the size of the indentation step; default size is <code>2</code>.
  331      * <p>
  332      * This is the number of spaces that lines will be indented (when appropriate).
  333      * 
  334      * @param newIndentationStep the new size of the indentation step.
  335      * @see #getIndentationStep
  336      */
  337     public void setIndentationStep(int newIndentationStep)
  338     {
  339   	indentationStep = (newIndentationStep < 0 ? 0 : newIndentationStep);
  340     }
  341     /**
  342      * Sets the (desired) maximum line length; default length is
  343      * <code>74</code>.
  344      * <p>
  345      * If a token is longer than the requested maximum line length,
  346      * then the line containing that token will obviously be longer
  347      * than the desired maximum.
  348      *
  349      * @param newMaxLineLength the new maximum line length.
  350      * @see #getMaxLineLength
  351      */
  352     public void setMaxLineLength(int newMaxLineLength)
  353     {
  354   	maxLineLength = (newMaxLineLength < 0 ? 0 : newMaxLineLength);
  355     }
  356     /**
  357      * Sets the set of sticky delimiters; default set is <code>","</code>.
  358      * <p>
  359      * Each character represents one sticky delimiter. If a line is ready
  360      * to be word-wrapped and a sticky delimiter is encountered, the sticky
  361      * delimiter will appear as the <em>last character on the current line</em>.
  362      * A quotation mark, <code>"</code> or <code>'</code>, closing a string
  363      * is always a sticky delimiter, whether you specify it or not.
  364      *
  365      * @param newStickyDelimiters the new set of sticky delimiters.
  366      * @see #getStickyDelimiters
  367      */
  368     public void setStickyDelimiters(String newStickyDelimiters)
  369     {
  370   	stickyDelimiters = newStickyDelimiters;
  371     }
  372   }

Save This Page
Home » bsf-src-2.4.0 » org.apache.bsf.util.cf » [javadoc | source]