FileDocCategorySizeDatePackage
CLArgsParser.javaAPI DocApache Axis 1.423358Sat Apr 22 18:57:26 BST 2006org.apache.axis.utils

CLArgsParser

public final class CLArgsParser extends Object
Parser for command line arguments. This parses command lines according to the standard (?) of GNU utilities. Note: This is still used in 1.1 libraries so do not add 1.2+ dependencies.
author
Peter Donald
since
4.0

Fields Summary
private static final int
STATE_NORMAL
private static final int
STATE_REQUIRE_2ARGS
private static final int
STATE_REQUIRE_ARG
private static final int
STATE_OPTIONAL_ARG
private static final int
STATE_NO_OPTIONS
private static final int
STATE_OPTION_MODE
private static final int
TOKEN_SEPARATOR
private static final int
TOKEN_STRING
private static final char[]
ARG2_SEPARATORS
private static final char[]
ARG_SEPARATORS
private static final char[]
NULL_SEPARATORS
private final CLOptionDescriptor[]
m_optionDescriptors
private final Vector
m_options
private Hashtable
m_optionIndex
private final ParserControl
m_control
private String
m_errorMessage
private String[]
m_unparsedArgs
private char
ch
private String[]
args
private boolean
isLong
private int
argIndex
private int
stringIndex
private int
stringLength
private static final int
INVALID
private int
m_lastChar
private int
m_lastOptionId
private CLOption
m_option
private int
m_state
Constructors Summary
public CLArgsParser(String[] args, CLOptionDescriptor[] optionDescriptors)
Create a parser that deals with options and parses certain args.

param
args the args
param
optionDescriptors the option descriptors

        this( args, optionDescriptors, null );
    
public CLArgsParser(String[] args, CLOptionDescriptor[] optionDescriptors, ParserControl control)
Create a parser that can deal with options and parses certain args.

param
args the args, typically that passed to the public static void main(String[] args) method.
param
optionDescriptors the option descriptors

        m_optionDescriptors = optionDescriptors;
        m_control = control;
        m_options = new Vector();
        this.args = args;

        try
        {
            parse();
            checkIncompatibilities( m_options );
            buildOptionIndex();
        }
        catch( final ParseException pe )
        {
            m_errorMessage = pe.getMessage();
        }

        //System.out.println( "Built : " + m_options );
        //System.out.println( "From : " + Arrays.asList( args ) );
    
Methods Summary
private final voidaddOption(CLOption option)

        m_options.addElement( option );
        m_lastOptionId = option.getId();
        m_option = null;
    
private final voidbuildOptionIndex()
Build the m_optionIndex lookup map for the parsed options.

        m_optionIndex = new Hashtable( m_options.size() * 2 );

        for( int i = 0; i < m_options.size(); i++ )
        {
            final CLOption option = (CLOption)m_options.get( i );
            final CLOptionDescriptor optionDescriptor =
                getDescriptorFor( option.getId() );

            m_optionIndex.put( new Integer( option.getId() ), option );

            if( null != optionDescriptor )
            {
                m_optionIndex.put( optionDescriptor.getName(), option );
            }
        }
    
private final voidcheckIncompatibilities(java.util.Vector arguments)
Check for duplicates of an option. It is an error to have duplicates unless appropriate flags is set in descriptor.

param
arguments the arguments

        final int size = arguments.size();

        for( int i = 0; i < size; i++ )
        {
            final CLOption option = (CLOption)arguments.elementAt( i );
            final int id = option.getId();
            final CLOptionDescriptor descriptor = getDescriptorFor( id );

            //this occurs when id == 0 and user has not supplied a descriptor
            //for arguments
            if( null == descriptor )
            {
                continue;
            }

            final int[] incompatible = descriptor.getIncompatible();

            checkIncompatible( arguments, incompatible, i );
        }
    
private final voidcheckIncompatible(java.util.Vector arguments, int[] incompatible, int original)

        final int size = arguments.size();

        for( int i = 0; i < size; i++ )
        {
            if( original == i )
            {
                continue;
            }

            final CLOption option = (CLOption)arguments.elementAt( i );
            final int id = option.getId();
//            final CLOptionDescriptor descriptor = getDescriptorFor( id );

            for( int j = 0; j < incompatible.length; j++ )
            {
                if( id == incompatible[ j ] )
                {
                    final CLOption originalOption = (CLOption)arguments.elementAt( original );
                    final int originalId = originalOption.getId();

                    String message = null;

                    if( id == originalId )
                    {
                        message =
                            "Duplicate options for " + describeDualOption( originalId ) +
                            " found.";
                    }
                    else
                    {
                        message = "Incompatible options -" +
                            describeDualOption( id ) + " and " +
                            describeDualOption( originalId ) + " found.";
                    }
                    throw new ParseException( message, 0 );
                }
            }
        }
    
private final java.lang.StringdescribeDualOption(int id)

        final CLOptionDescriptor descriptor = getDescriptorFor( id );
        if( null == descriptor )
        {
            return "<parameter>";
        }
        else
        {
            final StringBuffer sb = new StringBuffer();
            boolean hasCharOption = false;

            if( Character.isLetter( (char)id ) )
            {
                sb.append( '-" );
                sb.append( (char)id );
                hasCharOption = true;
            }

            final String longOption = descriptor.getName();
            if( null != longOption )
            {
                if( hasCharOption )
                {
                    sb.append( '/" );
                }
                sb.append( "--" );
                sb.append( longOption );
            }

            return sb.toString();
        }
    
public final CLOptiongetArgumentById(int id)
Retrieve the {@link CLOption} with specified id, or null if no command line option is found.

param
id the command line option id
return
the {@link CLOption} with the specified id, or null if no CLOption is found.
see
CLOption

        return (CLOption)m_optionIndex.get( new Integer( id ) );
    
public final CLOptiongetArgumentByName(java.lang.String name)
Retrieve the {@link CLOption} with specified name, or null if no command line option is found.

param
name the command line option name
return
the {@link CLOption} with the specified name, or null if no CLOption is found.
see
CLOption

        return (CLOption)m_optionIndex.get( name );
    
public final java.util.VectorgetArguments()
Retrieve a list of options that were parsed from command list.

return
the list of options

        //System.out.println( "Arguments: " + m_options );
        return m_options;
    
private final chargetChar()

        if( INVALID != m_lastChar )
        {
            final char result = (char)m_lastChar;
            m_lastChar = INVALID;
            return result;
        }
        else
        {
            return readChar();
        }
    
private final CLOptionDescriptorgetDescriptorFor(int id)
Get Descriptor for option id.

param
id the id
return
the descriptor

        for( int i = 0; i < m_optionDescriptors.length; i++ )
        {
            if( m_optionDescriptors[i].getId() == id )
            {
                return m_optionDescriptors[i];
            }
        }

        return null;
    
private final CLOptionDescriptorgetDescriptorFor(java.lang.String name)
Retrieve a descriptor by name.

param
name the name
return
the descriptor

        for( int i = 0; i < m_optionDescriptors.length; i++ )
        {
            if( m_optionDescriptors[i].getName().equals( name ) )
            {
                return m_optionDescriptors[i];
            }
        }

        return null;
    
public final java.lang.StringgetErrorString()
Retrieve an error message that occured during parsing if one existed.

return
the error string

        //System.out.println( "ErrorString: " + m_errorMessage );
        return m_errorMessage;
    
private final java.lang.StringgetOptionDescription(CLOptionDescriptor descriptor)

        if( isLong )
        {
            return "--" + descriptor.getName();
        }
        else
        {
            return "-" + (char)descriptor.getId();
        }
    
private final intgetStateFor(CLOptionDescriptor descriptor)
Require state to be placed in for option.

param
descriptor the Option Descriptor
return
the state

        int flags = descriptor.getFlags();
        if( ( flags & CLOptionDescriptor.ARGUMENTS_REQUIRED_2 ) ==
            CLOptionDescriptor.ARGUMENTS_REQUIRED_2 )
        {
            return STATE_REQUIRE_2ARGS;
        }
        else if( ( flags & CLOptionDescriptor.ARGUMENT_REQUIRED ) ==
                 CLOptionDescriptor.ARGUMENT_REQUIRED )
        {
            return STATE_REQUIRE_ARG;
        }
        else if( ( flags & CLOptionDescriptor.ARGUMENT_OPTIONAL ) ==
                 CLOptionDescriptor.ARGUMENT_OPTIONAL )
        {
            return STATE_OPTIONAL_ARG;
        }
        else
        {
            return STATE_NORMAL;
        }
    
public final java.lang.String[]getUnparsedArgs()


       
    
        return m_unparsedArgs;
    
private final booleanisSeparator(char ch, char[] separators)

        for( int i = 0; i < separators.length; i++ )
        {
            if( ch == separators[ i ] )
            {
                return true;
            }
        }

        return false;
    
private final TokennextToken(char[] separators)

        ch = getChar();

        if( isSeparator( ch, separators ) )
        {
            ch = getChar();
            return new Token( TOKEN_SEPARATOR, null );
        }

        final StringBuffer sb = new StringBuffer();

        do
        {
            sb.append( ch );
            ch = getChar();
        }
        while( !isSeparator( ch, separators ) );

        return new Token( TOKEN_STRING, sb.toString() );
    
private final voidparse()
Actually parse arguments

param
args[] arguments

        if( 0 == args.length )
        {
            return;
        }

        stringLength = args[ argIndex ].length();

        //ch = peekAtChar();

        while( true )
        {
            ch = peekAtChar();

            //System.out.println( "Pre State=" + m_state );
            //System.out.println( "Pre Char=" + (char)ch + "/" + (int)ch );

            if( argIndex >= args.length )
            {
                break;
            }

            if( null != m_control && m_control.isFinished( m_lastOptionId ) )
            {
                //this may need mangling due to peeks
                m_unparsedArgs = subArray( args, argIndex, stringIndex );
                return;
            }

            //System.out.println( "State=" + m_state );
            //System.out.println( "Char=" + (char)ch + "/" + (int)ch );

            if( STATE_OPTION_MODE == m_state )
            {
                //if get to an arg barrier then return to normal mode
                //else continue accumulating options
                if( 0 == ch )
                {
                    getChar(); //strip the null
                    m_state = STATE_NORMAL;
                }
                else
                {
                    parseShortOption();
                }
            }
            else if( STATE_NORMAL == m_state )
            {
                parseNormal();
            }
            else if( STATE_NO_OPTIONS == m_state )
            {
                //should never get to here when stringIndex != 0
                addOption( new CLOption( args[ argIndex++ ] ) );
            }
            else if( STATE_OPTIONAL_ARG == m_state && '-" == ch )
            {
                m_state = STATE_NORMAL;
                addOption( m_option );
            }
            else
            {
                parseArguments();
            }
        }

        if( m_option != null )
        {
            if( STATE_OPTIONAL_ARG == m_state )
            {
                m_options.addElement( m_option );
            }
            else if( STATE_REQUIRE_ARG == m_state )
            {
                final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                final String message =
                    "Missing argument to option " + getOptionDescription( descriptor );
                throw new ParseException( message, 0 );
            }
            else if( STATE_REQUIRE_2ARGS == m_state )
            {
                if( 1 == m_option.getArgumentCount() )
                {
                    m_option.addArgument( "" );
                    m_options.addElement( m_option );
                }
                else
                {
                    final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                    final String message =
                        "Missing argument to option " + getOptionDescription( descriptor );
                    throw new ParseException( message, 0 );
                }
            }
            else
            {
                throw new ParseException( "IllegalState " + m_state + ": " + m_option, 0 );
            }
        }
    
private final voidparseArguments()

        if( STATE_REQUIRE_ARG == m_state )
        {
            if( '=" == ch || 0 == ch )
            {
                getChar();
            }

            final Token token = nextToken( NULL_SEPARATORS );
            m_option.addArgument( token.getValue() );

            addOption( m_option );
            m_state = STATE_NORMAL;
        }
        else if( STATE_OPTIONAL_ARG == m_state )
        {
            if( '-" == ch || 0 == ch )
            {
                getChar(); //consume stray character
                addOption( m_option );
                m_state = STATE_NORMAL;
                return;
            }

            if( '=" == ch )
            {
                getChar();
            }

            final Token token = nextToken( NULL_SEPARATORS );
            m_option.addArgument( token.getValue() );

            addOption( m_option );
            m_state = STATE_NORMAL;
        }
        else if( STATE_REQUIRE_2ARGS == m_state )
        {
            if( 0 == m_option.getArgumentCount() )
            {
                final Token token = nextToken( ARG_SEPARATORS );

                if( TOKEN_SEPARATOR == token.getType() )
                {
                    final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                    final String message =
                        "Unable to parse first argument for option " +
                        getOptionDescription( descriptor );
                    throw new ParseException( message, 0 );
                }
                else
                {
                    m_option.addArgument( token.getValue() );
                }
            }
            else //2nd argument
            {
                final StringBuffer sb = new StringBuffer();

                ch = getChar();
                if( '-" == ch )
                {
                    m_lastChar = ch;
                }

                while( !isSeparator( ch, ARG2_SEPARATORS ) )
                {
                    sb.append( ch );
                    ch = getChar();
                }

                final String argument = sb.toString();

                //System.out.println( "Arguement:" + argument );

                m_option.addArgument( argument );
                addOption( m_option );
                m_option = null;
                m_state = STATE_NORMAL;
            }
        }
    
private final voidparseNormal()
Parse Options from Normal mode.

        if( '-" != ch )
        {
            //Parse the arguments that are not options
            final String argument = nextToken( NULL_SEPARATORS ).getValue();
            addOption( new CLOption( argument ) );
            m_state = STATE_NORMAL;
        }
        else
        {
            getChar(); // strip the -

            if( 0 == peekAtChar() )
            {
                throw new ParseException( "Malformed option -", 0 );
            }
            else
            {
                ch = peekAtChar();

                //if it is a short option then parse it else ...
                if( '-" != ch )
                {
                    parseShortOption();
                }
                else
                {
                    getChar(); // strip the -
                    //-- sequence .. it can either mean a change of state
                    //to STATE_NO_OPTIONS or else a long option

                    if( 0 == peekAtChar() )
                    {
                        getChar();
                        m_state = STATE_NO_OPTIONS;
                    }
                    else
                    {
                        //its a long option
                        final String optionName = nextToken( ARG_SEPARATORS ).getValue();
                        final CLOptionDescriptor descriptor = getDescriptorFor( optionName );
                        isLong = true;
                        parseOption( descriptor, "--" + optionName );
                    }
                }
            }
        }
    
private final voidparseOption(CLOptionDescriptor descriptor, java.lang.String optionString)

        if( null == descriptor )
        {
            throw new ParseException( "Unknown option " + optionString, 0 );
        }

        m_state = getStateFor( descriptor );
        m_option = new CLOption( descriptor.getId() );

        if( STATE_NORMAL == m_state )
        {
            addOption( m_option );
        }
    
private final voidparseShortOption()

        ch = getChar();
        final CLOptionDescriptor descriptor = getDescriptorFor( ch );
        isLong = false;
        parseOption( descriptor, "-" + ch );

        if( STATE_NORMAL == m_state )
        {
            m_state = STATE_OPTION_MODE;
        }
    
private final charpeekAtChar()

        if( INVALID == m_lastChar )
        {
            m_lastChar = readChar();
        }
        return (char)m_lastChar;
    
private final charreadChar()

        if( stringIndex >= stringLength )
        {
            argIndex++;
            stringIndex = 0;

            if( argIndex < args.length )
            {
                stringLength = args[ argIndex ].length();
            }
            else
            {
                stringLength = 0;
            }

            return 0;
        }

        if( argIndex >= args.length )
            return 0;

        return args[ argIndex ].charAt( stringIndex++ );
    
private final java.lang.String[]subArray(java.lang.String[] array, int index, int charIndex)
Create a string array that is subset of input array. The sub-array should start at array entry indicated by index. That array element should only include characters from charIndex onwards.

param
array[] the original array
param
index the cut-point in array
param
charIndex the cut-point in element of array
return
the result array

        final int remaining = array.length - index;
        final String[] result = new String[ remaining ];

        if( remaining > 1 )
        {
            System.arraycopy( array, index + 1, result, 1, remaining - 1 );
        }

        result[0] = array[ index ].substring( charIndex - 1 );

        return result;