/* XBN Java: Generically useful, non-GUI Java code. http://sourceforge.net/projects/xbnjava Copyright (C) 1997-2003, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package xbn.jdlcode; import xbn.XBNObject; import xbn.array.VWObject; import xbn.array.primitive.PASAOObject; import xbn.string.UtilString; import java.util.StringTokenizer; /**

Example link: <A HREF="\~JD\~t\~EJD\~">\~JD\~t\~EJD\~</a>  -->  ~JD~t~EJD~ (see package description for details).

Source code:  SplitLinkCode.java

SplitLinkCode takes the code of a JavaDoc Link Code, and splits it into it's fundamental parts: Class name, function/constructor name, and parameters. It can then take these pieces and generate the actual link.

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class SplitLinkCode extends XBNObject { //ENTIRE strings used four or more times. private static final String sQT_PD = "'."; private static final String sPD = "."; private UtilString uStr = new UtilString(); private UtilJDLCode uJDLink = new UtilJDLCode(); private String sClass = null; private String sFunction = null; private Parameter[] aParameters = null; /**

Create a SplitLinkCode.

The form of a JavaDoc Link Code is the following:

class_abbrev#function_constructor_abbrev(parameter1[],parameter2[],...)

@param s_linkCode The string containing the JavaDoc Link Code. Must conform to the following rules:

 

**/ public SplitLinkCode(String s_linkCode) { if((s_linkCode == null || s_linkCode.length() < 1)) { throwAX("constructor: s_linkCode must be non null, and at least one character in length."); } if(!Character.isLetterOrDigit(s_linkCode.charAt(0)) && s_linkCode.charAt(0) != '_') { throwAX("constructor: The first charactor of s_linkCode ('" + s_linkCode + "') must be a letter, digit or underscore.."); } if(!Character.isLetterOrDigit(s_linkCode.charAt(s_linkCode.length() - 1)) && s_linkCode.charAt(s_linkCode.length() - 1) != '_' && s_linkCode.charAt(s_linkCode.length() - 1) != ')') { throwAX("constructor: The last charactor of s_linkCode ('" + s_linkCode + "') must be a letter, digit, underscore or close paren (')')."); } int iOpenParen1st = s_linkCode.indexOf("("); int iOpenParenLast = s_linkCode.lastIndexOf("("); int iCloseParen1st = s_linkCode.indexOf(")"); int iCloseParenLast = s_linkCode.lastIndexOf(")"); int iNumberSign1st = s_linkCode.indexOf("#"); int iNumberSignLast = s_linkCode.lastIndexOf("#"); int iComma1st = s_linkCode.lastIndexOf(","); int iCommaLast = s_linkCode.lastIndexOf(","); if((iOpenParen1st == -1 && iCloseParen1st != -1) || (iOpenParen1st != -1 && iCloseParen1st == -1)) { throwAX("constructor: Either both parens must exist, or neither must exist. '(' exists? " + (iOpenParen1st != -1) + ". ')' exists? " + (iCloseParen1st != -1) + ". s_linkCode='" + s_linkCode + sQT_PD); } //The parenthesis either both exist or both don't exist. boolean bParensExist = (iOpenParen1st != -1); if(bParensExist) { if((iOpenParen1st != -1 && iOpenParenLast != -1 && iOpenParen1st != iOpenParenLast) || (iCloseParen1st != -1 && iCloseParenLast != -1 && iCloseParen1st != iCloseParenLast)) { throwAX("constructor: Only one set of parenthesis may exist in a link. s_linkCode='" + s_linkCode + sQT_PD); } if(iCloseParen1st != (s_linkCode.length() - 1)) { throwAX("constructor: Parenthesis do exist, but the close parenthesis is not the last character. Currently " + iCloseParen1st + " (length=" + s_linkCode.length() + ")."); } if(iOpenParen1st > iCloseParen1st) { throwAX("constructor: Parenthesis do exist, but the open parenthesis exists after the close. s_linkCode='" + s_linkCode + sQT_PD); } if(iNumberSign1st != -1 && iNumberSign1st > iOpenParen1st) { throwAX("constructor: Both parenthesis and a number sign exist, but the number sign must precede the parenthesis. s_linkCode='" + s_linkCode + sQT_PD); } if(iComma1st != -1 && (iComma1st < iOpenParen1st || iCommaLast > iCloseParen1st)) { throwAX("constructor: Both parenthesis and at least one comma exist, but I found comma either after the open paren, or after the close one (or both). s_linkCode='" + s_linkCode + sQT_PD); } if(iNumberSign1st != -1 && iNumberSignLast != -1 && iNumberSign1st != iNumberSignLast) { throwAX("constructor: Only one number sign may exist in a link. s_linkCode='" + s_linkCode + sQT_PD); } } else { if(iComma1st != -1) { throwAX("constructor: No parenthesis exist, but a comma does. Commas only belong in the middle of parenthesis. s_linkCode='" + s_linkCode + sQT_PD); } if(iNumberSign1st != -1) { throwAX("constructor: Parenthesis do not exist, but number sign does. A number sign must always be followed by a function, which must have parenthesis. To link to a name href (instead of a function), put the '#name_href_name' *after* the closing gap text ('" + uJDLink.getJDLinkGapEnd() + "'). s_linkCode='" + s_linkCode + sQT_PD); } } if(iNumberSign1st == -1 && !bParensExist) { sClass = s_linkCode; sFunction = null; aParameters = null; if(!uStr.isLetterDigitUnderscore(sClass)) { throwAX("constructor: A class name does exist ('" + sClass + "'), but has illegal characters. Only letters, digits and underscores are allowed. s_linkCode='" + s_linkCode + sQT_PD); } } else { if(iNumberSign1st == -1 && bParensExist) { sClass = null; sFunction = s_linkCode.substring(0, iOpenParen1st); aParameters = getAOParameters(s_linkCode, iOpenParen1st); } else if(iNumberSign1st != -1 && bParensExist) { sClass = s_linkCode.substring(0, iNumberSign1st); sFunction = s_linkCode.substring((iNumberSign1st + 1), iOpenParen1st); aParameters = getAOParameters(s_linkCode, iOpenParen1st); if(sClass.length() < 1) { throwAX("constructor: The class name must be at least one character in length. s_linkCode='" + s_linkCode + sQT_PD); } if(!uStr.isLetterDigitUnderscore(sClass)) { throwAX("constructor: A class name does exist ('" + sClass + "'), but has illegal characters. Only letters, digits and underscores are allowed. s_linkCode='" + s_linkCode + sQT_PD); } } if(sFunction.length() < 1) { throwAX("constructor: The function name must be at least one character in length. s_linkCode='" + s_linkCode + sQT_PD); } if(!uStr.isLetterDigitUnderscore(sFunction)) { throwAX("constructor: A function name does exist ('" + sFunction + "'), but has illegal characters. Only letters, digits and underscores are allowed. s_linkCode='" + s_linkCode + sQT_PD); } } } /**

What is the class name in this link?

@return The class name if one exists, or
null if none exists. **/ public String getClassName() { return sClass; } /**

What is the function name in this link?

@return The function name if one exists, or
null if none exists. **/ public String getCnstrFuncName() { return sFunction; } /**

How many parameters exist in this link?

@return 0 or higher, representing the number of parameters.. **/ public int getParameterCount() { if(aParameters == null) { return 0; } return aParameters.length; } /**

How many parameters are arrays?

@return 0..[getParameterCount], representing the number of parameters that have "[]" following it. **/ public int getParamIsArrayCount() { if(getParameterCount() == 0) { return 0; } int iCount = 0; for(int i = 0; i < getParameterCount(); i++) { if(isParamArray(i)) { iCount++; } } return iCount; } /**

Get the parameter at the requested array index.

@param i_dx The array index of the parameter. Must range zero..[getParameterCount - 1], inclusive. @exception AssertException If getParameterCount equals zero. **/ public String getParamName(int i_dx) { try { return aParameters[i_dx].sName; } catch(ArrayIndexOutOfBoundsException aioobx) { throwAX("getParamName: i_dx (" + i_dx + ") is invalid. getParameterCount()=" + getParameterCount() + "."); } //Never reached. Required for compile. return null; } /**

Is the parameter at the requested array index an array?

@param i_dx The array index of the parameter. Must range zero..[getParameterCount - 1], inclusive. @exception AssertException If getParameterCount equals zero. **/ public boolean isParamArray(int i_dx) { try { return aParameters[i_dx].bArray; } catch(ArrayIndexOutOfBoundsException aioobx) { throwAX("isParamArray: i_dx (" + i_dx + ") is invalid. getParameterCount()=" + getParameterCount() + "."); } //Never reached. Required for compile. return false; } public final String getParamList(String s_divider) { return (new PASParameter(aParameters)).getList(s_divider); } private final Parameter[] getAOParameters(String s_linkCode, int i_openParen1st) { String sAllParameters = s_linkCode.substring((i_openParen1st + 1), (s_linkCode.length() - 1)); StringTokenizer st = new StringTokenizer(sAllParameters, ",", true); if(st.countTokens() == 0) { return null; } VWObject vwo = new VWObject(); int iCommas = 0; while(st.hasMoreTokens()) { String s = st.nextToken(); if(!s.equals(",")) { Parameter p = new Parameter(); if(s.endsWith("[]")) { p.bArray = true; s = s.substring(0, (s.length() - 2)); if(s.length() < 1) { throwAX("Array parameter found, but no class abbreviation exists before '[]'"); } } else { p.bArray = false; } if(!uStr.isLetterDigitUnderscore(s)) { throwAX("constructor: The parameter abbreviation '" + s + " has illegal characters. Must only contain letters digits and underscores. If it is an array, then [] must exist between the parameter abbreviation and comma. Spaces are illegal."); } p.sName = s; vwo.add(p); } else { iCommas++; } } if(iCommas != (vwo.size() - 1)) { throwAX("constructor: There is/are " + iCommas + " comma(s) between the parenthesis, and " + vwo.size() + " parameter(s). Each parameter must be at least one character in length."); } Object[] ao = vwo.getAOObject(); aParameters = new Parameter[ao.length]; for(int i = 0; i < aParameters.length; i++) { aParameters[i] = (Parameter)ao[i]; } return aParameters; } } class Parameter { public String sName = null; public boolean bArray = false; } class PASParameter extends PASAOObject { public PASParameter(Parameter[] a_parameters) { super("xbn.jdlcode.SplitLinkCode$PASParameter", a_parameters); } public final Parameter getParameter(int i_dx) { return (Parameter)getObject(i_dx); } public final String getString(int i_dx) { Parameter p = getParameter(i_dx); return (p.bArray) ? p.sName + "[]" : p.sName; } public final Parameter[] getAOParameter() { return (Parameter[])getAOObject(); } }