avalon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From leosu...@apache.org
Subject cvs commit: avalon-excalibur/compatibility/src/java/org/apache/avalon/excalibur/cli CLArgsParser.java CLOption.java
Date Mon, 24 Mar 2003 09:03:33 GMT
leosutic    2003/03/24 01:03:32

  Modified:    compatibility/src/java/org/apache/avalon/excalibur/cli
                        CLArgsParser.java CLOption.java
  Log:
  Fixes incompatibility due to a null Descriptor being exposed instead of a
  default text argument descriptor.
  
  Also, fixed line endings for CLArgsParser: CR CR LF -> LF
  
  Revision  Changes    Path
  1.5       +782 -782  avalon-excalibur/compatibility/src/java/org/apache/avalon/excalibur/cli/CLArgsParser.java
  
  Index: CLArgsParser.java
  ===================================================================
  RCS file: /home/cvs/avalon-excalibur/compatibility/src/java/org/apache/avalon/excalibur/cli/CLArgsParser.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- CLArgsParser.java	22 Mar 2003 12:46:22 -0000	1.4
  +++ CLArgsParser.java	24 Mar 2003 09:03:32 -0000	1.5
  @@ -46,785 +46,785 @@
    on  behalf of the Apache Software  Foundation. For more  information on the 
    Apache Software Foundation, please see <http://www.apache.org/>.
    
  -*/
  -package org.apache.avalon.excalibur.cli;
  -
  -import java.text.ParseException;
  -import java.util.Hashtable;
  -import java.util.Vector;
  -
  -/**
  - * 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.
  - *
  - * Note that CLArgs uses a backing hashtable for the options index and so duplicate
  - * arguments are only returned by getArguments(). 
  - *
  - * @author <a href="mailto:peter at apache.org">Peter Donald</a>
  - * @version $Revision$ $Date$
  - * @since 4.0
  - * @see ParserControl
  - * @see CLOption
  - * @see CLOptionDescriptor
  - */
  -public final class CLArgsParser
  -{
  -    //cached character == Integer.MAX_VALUE when invalid
  -    private static final int INVALID = Integer.MAX_VALUE;
  -
  -    private static final int STATE_NORMAL = 0;
  -    private static final int STATE_REQUIRE_2ARGS = 1;
  -    private static final int STATE_REQUIRE_ARG = 2;
  -    private static final int STATE_OPTIONAL_ARG = 3;
  -    private static final int STATE_NO_OPTIONS = 4;
  -    private static final int STATE_OPTION_MODE = 5;
  -
  -    private static final int TOKEN_SEPARATOR = 0;
  -    private static final int TOKEN_STRING = 1;
  -
  -    private static final char[] ARG2_SEPARATORS =
  -        new char[]{(char)0, '=', '-'};
  -
  -    private static final char[] ARG_SEPARATORS =
  -        new char[]{(char)0, '='};
  -
  -    private static final char[] NULL_SEPARATORS =
  -        new char[]{(char)0};
  -
  -    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 = new String[]{};
  -
  -    //variables used while parsing options.
  -    private char m_ch;
  -    private String[] m_args;
  -    private boolean m_isLong;
  -    private int m_argIndex;
  -    private int m_stringIndex;
  -    private int m_stringLength;
  -
  -    private int m_lastChar = INVALID;
  -
  -    private int m_lastOptionId;
  -    private CLOption m_option;
  -    private int m_state = STATE_NORMAL;
  -
  -    /**
  -     * Retrieve an array of arguments that have not been parsed
  -     * due to the parser halting.
  -     *
  -     * @return an array of unparsed args
  -     */
  -    public final String[] getUnparsedArgs()
  -    {
  -        return m_unparsedArgs;
  -    }
  -
  -    /**
  -     * Retrieve a list of options that were parsed from command list.
  -     *
  -     * @return the list of options
  -     */
  -    public final Vector getArguments()
  -    {
  -        //System.out.println( "Arguments: " + m_options );
  -        return m_options;
  -    }
  -
  -    /**
  -     * Retrieve the {@link CLOption} with specified id, or
  -     * <code>null</code> if no command line option is found.
  -     *
  -     * @param id the command line option id
  -     * @return the {@link CLOption} with the specified id, or
  -     *    <code>null</code> if no CLOption is found.
  -     * @see CLOption
  -     */
  -    public final CLOption getArgumentById( final int id )
  -    {
  -        return (CLOption)m_optionIndex.get( new Integer( id ) );
  -    }
  -
  -    /**
  -     * Retrieve the {@link CLOption} with specified name, or
  -     * <code>null</code> if no command line option is found.
  -     *
  -     * @param name the command line option name
  -     * @return the {@link CLOption} with the specified name, or
  -     *    <code>null</code> if no CLOption is found.
  -     * @see CLOption
  -     */
  -    public final CLOption getArgumentByName( final String name )
  -    {
  -        return (CLOption)m_optionIndex.get( name );
  -    }
  -
  -    /**
  -     * Get Descriptor for option id.
  -     *
  -     * @param id the id
  -     * @return the descriptor
  -     */
  -    private final CLOptionDescriptor getDescriptorFor( final int id )
  -    {
  -        for( int i = 0; i < m_optionDescriptors.length; i++ )
  -        {
  -            if( m_optionDescriptors[ i ].getId() == id )
  -            {
  -                return m_optionDescriptors[ i ];
  -            }
  -        }
  -
  -        return null;
  -    }
  -
  -    /**
  -     * Retrieve a descriptor by name.
  -     *
  -     * @param name the name
  -     * @return the descriptor
  -     */
  -    private final CLOptionDescriptor getDescriptorFor( final String name )
  -    {
  -        for( int i = 0; i < m_optionDescriptors.length; i++ )
  -        {
  -            if( m_optionDescriptors[ i ].getName().equals( name ) )
  -            {
  -                return m_optionDescriptors[ i ];
  -            }
  -        }
  -
  -        return null;
  -    }
  -
  -    /**
  -     * Retrieve an error message that occured during parsing if one existed.
  -     *
  -     * @return the error string
  -     */
  -    public final String getErrorString()
  -    {
  -        //System.out.println( "ErrorString: " + m_errorMessage );
  -        return m_errorMessage;
  -    }
  -
  -    /**
  -     * Require state to be placed in for option.
  -     *
  -     * @param descriptor the Option Descriptor
  -     * @return the state
  -     */
  -    private final int getStateFor( final CLOptionDescriptor descriptor )
  -    {
  -        final 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;
  -        }
  -    }
  -
  -    /**
  -     * Create a parser that can deal with options and parses certain args.
  -     *
  -     * @param args the args, typically that passed to the
  -     * <code>public static void main(String[] args)</code> method.
  -     * @param optionDescriptors the option descriptors
  -     * @param control the parser control used determine behaviour of parser
  -     */
  -    public CLArgsParser( final String[] args,
  -                         final CLOptionDescriptor[] optionDescriptors,
  -                         final ParserControl control )
  -    {
  -        m_optionDescriptors = optionDescriptors;
  -        m_control = control;
  -        m_options = new Vector();
  -        m_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 ) );
  -    }
  -
  -    /**
  -     * Check for duplicates of an option.
  -     * It is an error to have duplicates unless appropriate flags is set in descriptor.
  -     *
  -     * @param arguments the arguments
  -     */
  -    private final void checkIncompatibilities( final Vector arguments )
  -        throws ParseException
  -    {
  -        final int size = arguments.size();
  -
  -        for( int i = 0; i < size; i++ )
  -        {
  -            final CLOption option = (CLOption)arguments.elementAt( i );
  -            final int id = option.getDescriptor().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 void checkIncompatible( final Vector arguments,
  -                                          final int[] incompatible,
  -                                          final int original )
  -        throws ParseException
  -    {
  -        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.getDescriptor().getId();
  -
  -            for( int j = 0; j < incompatible.length; j++ )
  -            {
  -                if( id == incompatible[ j ] )
  -                {
  -                    final CLOption originalOption = (CLOption)arguments.elementAt( original );
  -                    final int originalId = originalOption.getDescriptor().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 String describeDualOption( final 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();
  -        }
  -    }
  -
  -    /**
  -     * Create a parser that deals with options and parses certain args.
  -     *
  -     * @param args the args
  -     * @param optionDescriptors the option descriptors
  -     */
  -    public CLArgsParser( final String[] args,
  -                         final CLOptionDescriptor[] optionDescriptors )
  -    {
  -        this( args, optionDescriptors, null );
  -    }
  -
  -    /**
  -     * 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
  -     */
  -    private final String[] subArray( final String[] array,
  -                                     final int index,
  -                                     final int charIndex )
  -    {
  -        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;
  -    }
  -
  -    /**
  -     * Actually parse arguments
  -     */
  -    private final void parse()
  -        throws ParseException
  -    {
  -        if( 0 == m_args.length )
  -        {
  -            return;
  -        }
  -
  -        m_stringLength = m_args[ m_argIndex ].length();
  -
  -        //ch = peekAtChar();
  -
  -        while( true )
  -        {
  -            m_ch = peekAtChar();
  -
  -            //System.out.println( "Pre State=" + m_state );
  -            //System.out.println( "Pre Char=" + (char)ch + "/" + (int)ch );
  -
  -            if( m_argIndex >= m_args.length )
  -            {
  -                break;
  -            }
  -
  -            if( null != m_control && m_control.isFinished( m_lastOptionId ) )
  -            {
  -                //this may need mangling due to peeks
  -                m_unparsedArgs = subArray( m_args, m_argIndex, m_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 == m_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( m_args[ m_argIndex++ ] ) );
  -            }
  -            else if( STATE_OPTIONAL_ARG == m_state && '-' == m_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.getDescriptor().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.getDescriptor().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 String getOptionDescription( final CLOptionDescriptor descriptor )
  -    {
  -        if( m_isLong )
  -        {
  -            return "--" + descriptor.getName();
  -        }
  -        else
  -        {
  -            return "-" + (char)descriptor.getId();
  -        }
  -    }
  -
  -    private final char peekAtChar()
  -    {
  -        if( INVALID == m_lastChar )
  -        {
  -            m_lastChar = readChar();
  -        }
  -        return (char)m_lastChar;
  -    }
  -
  -    private final char getChar()
  -    {
  -        if( INVALID != m_lastChar )
  -        {
  -            final char result = (char)m_lastChar;
  -            m_lastChar = INVALID;
  -            return result;
  -        }
  -        else
  -        {
  -            return readChar();
  -        }
  -    }
  -
  -    private final char readChar()
  -    {
  -        if( m_stringIndex >= m_stringLength )
  -        {
  -            m_argIndex++;
  -            m_stringIndex = 0;
  -
  -            if( m_argIndex < m_args.length )
  -            {
  -                m_stringLength = m_args[ m_argIndex ].length();
  -            }
  -            else
  -            {
  -                m_stringLength = 0;
  -            }
  -
  -            return 0;
  -        }
  -
  -        if( m_argIndex >= m_args.length )
  -        {
  -            return 0;
  -        }
  -
  -        return m_args[ m_argIndex ].charAt( m_stringIndex++ );
  -    }
  -
  -    private final Token nextToken( final char[] separators )
  -    {
  -        m_ch = getChar();
  -
  -        if( isSeparator( m_ch, separators ) )
  -        {
  -            m_ch = getChar();
  -            return new Token( TOKEN_SEPARATOR, null );
  -        }
  -
  -        final StringBuffer sb = new StringBuffer();
  -
  -        do
  -        {
  -            sb.append( m_ch );
  -            m_ch = getChar();
  -        } while( !isSeparator( m_ch, separators ) );
  -
  -        return new Token( TOKEN_STRING, sb.toString() );
  -    }
  -
  -    private final boolean isSeparator( final char ch, final char[] separators )
  -    {
  -        for( int i = 0; i < separators.length; i++ )
  -        {
  -            if( ch == separators[ i ] )
  -            {
  -                return true;
  -            }
  -        }
  -
  -        return false;
  -    }
  -
  -    private final void addOption( final CLOption option )
  -    {
  -        m_options.addElement( option );
  -        m_lastOptionId = option.getDescriptor().getId();
  -        m_option = null;
  -    }
  -
  -    private final void parseOption( final CLOptionDescriptor descriptor,
  -                                    final String optionString )
  -        throws ParseException
  -    {
  -        if( null == descriptor )
  -        {
  -            throw new ParseException( "Unknown option " + optionString, 0 );
  -        }
  -
  -        m_state = getStateFor( descriptor );
  -        m_option = new CLOption( descriptor );
  -
  -        if( STATE_NORMAL == m_state )
  -        {
  -            addOption( m_option );
  -        }
  -    }
  -
  -    private final void parseShortOption()
  -        throws ParseException
  -    {
  -        m_ch = getChar();
  -        final CLOptionDescriptor descriptor = getDescriptorFor( m_ch );
  -        m_isLong = false;
  -        parseOption( descriptor, "-" + m_ch );
  -
  -        if( STATE_NORMAL == m_state )
  -        {
  -            m_state = STATE_OPTION_MODE;
  -        }
  -    }
  -
  -    private final void parseArguments()
  -        throws ParseException
  -    {
  -        if( STATE_REQUIRE_ARG == m_state )
  -        {
  -            if( '=' == m_ch || 0 == m_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( '-' == m_ch || 0 == m_ch )
  -            {
  -                getChar(); //consume stray character
  -                addOption( m_option );
  -                m_state = STATE_NORMAL;
  -                return;
  -            }
  -
  -            if( '=' == m_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.getDescriptor().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();
  -
  -                m_ch = getChar();
  -                if( '-' == m_ch )
  -                {
  -                    m_lastChar = m_ch;
  -                }
  -
  -                while( !isSeparator( m_ch, ARG2_SEPARATORS ) )
  -                {
  -                    sb.append( m_ch );
  -                    m_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;
  -            }
  -        }
  -    }
  -
  -    /**
  -     * Parse Options from Normal mode.
  -     */
  -    private final void parseNormal()
  -        throws ParseException
  -    {
  -        if( '-' != m_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
  -            {
  -                m_ch = peekAtChar();
  -
  -                //if it is a short option then parse it else ...
  -                if( '-' != m_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 );
  -                        m_isLong = true;
  -                        parseOption( descriptor, "--" + optionName );
  -                    }
  -                }
  -            }
  -        }
  -    }
  -
  -    /**
  -     * Build the m_optionIndex lookup map for the parsed options.
  -     */
  -    private final void buildOptionIndex()
  -    {
  -        final int size = m_options.size();
  -        m_optionIndex = new Hashtable( size * 2 );
  -
  -        for( int i = 0; i < size; i++ )
  -        {
  -            final CLOption option = (CLOption)m_options.get( i );
  -            final CLOptionDescriptor optionDescriptor =
  -                getDescriptorFor( option.getDescriptor().getId() );
  -
  -            m_optionIndex.put( new Integer( option.getDescriptor().getId() ), option );
  -
  -            if( null != optionDescriptor &&
  -                null != optionDescriptor.getName() )
  -            {
  -                m_optionIndex.put( optionDescriptor.getName(), option );
  -            }
  -        }
  -    }
  -}
  +*/
  +package org.apache.avalon.excalibur.cli;
  +
  +import java.text.ParseException;
  +import java.util.Hashtable;
  +import java.util.Vector;
  +
  +/**
  + * 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.
  + *
  + * Note that CLArgs uses a backing hashtable for the options index and so duplicate
  + * arguments are only returned by getArguments(). 
  + *
  + * @author <a href="mailto:peter at apache.org">Peter Donald</a>
  + * @version $Revision$ $Date$
  + * @since 4.0
  + * @see ParserControl
  + * @see CLOption
  + * @see CLOptionDescriptor
  + */
  +public final class CLArgsParser
  +{
  +    //cached character == Integer.MAX_VALUE when invalid
  +    private static final int INVALID = Integer.MAX_VALUE;
  +
  +    private static final int STATE_NORMAL = 0;
  +    private static final int STATE_REQUIRE_2ARGS = 1;
  +    private static final int STATE_REQUIRE_ARG = 2;
  +    private static final int STATE_OPTIONAL_ARG = 3;
  +    private static final int STATE_NO_OPTIONS = 4;
  +    private static final int STATE_OPTION_MODE = 5;
  +
  +    private static final int TOKEN_SEPARATOR = 0;
  +    private static final int TOKEN_STRING = 1;
  +
  +    private static final char[] ARG2_SEPARATORS =
  +        new char[]{(char)0, '=', '-'};
  +
  +    private static final char[] ARG_SEPARATORS =
  +        new char[]{(char)0, '='};
  +
  +    private static final char[] NULL_SEPARATORS =
  +        new char[]{(char)0};
  +
  +    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 = new String[]{};
  +
  +    //variables used while parsing options.
  +    private char m_ch;
  +    private String[] m_args;
  +    private boolean m_isLong;
  +    private int m_argIndex;
  +    private int m_stringIndex;
  +    private int m_stringLength;
  +
  +    private int m_lastChar = INVALID;
  +
  +    private int m_lastOptionId;
  +    private CLOption m_option;
  +    private int m_state = STATE_NORMAL;
  +
  +    /**
  +     * Retrieve an array of arguments that have not been parsed
  +     * due to the parser halting.
  +     *
  +     * @return an array of unparsed args
  +     */
  +    public final String[] getUnparsedArgs()
  +    {
  +        return m_unparsedArgs;
  +    }
  +
  +    /**
  +     * Retrieve a list of options that were parsed from command list.
  +     *
  +     * @return the list of options
  +     */
  +    public final Vector getArguments()
  +    {
  +        //System.out.println( "Arguments: " + m_options );
  +        return m_options;
  +    }
  +
  +    /**
  +     * Retrieve the {@link CLOption} with specified id, or
  +     * <code>null</code> if no command line option is found.
  +     *
  +     * @param id the command line option id
  +     * @return the {@link CLOption} with the specified id, or
  +     *    <code>null</code> if no CLOption is found.
  +     * @see CLOption
  +     */
  +    public final CLOption getArgumentById( final int id )
  +    {
  +        return (CLOption)m_optionIndex.get( new Integer( id ) );
  +    }
  +
  +    /**
  +     * Retrieve the {@link CLOption} with specified name, or
  +     * <code>null</code> if no command line option is found.
  +     *
  +     * @param name the command line option name
  +     * @return the {@link CLOption} with the specified name, or
  +     *    <code>null</code> if no CLOption is found.
  +     * @see CLOption
  +     */
  +    public final CLOption getArgumentByName( final String name )
  +    {
  +        return (CLOption)m_optionIndex.get( name );
  +    }
  +
  +    /**
  +     * Get Descriptor for option id.
  +     *
  +     * @param id the id
  +     * @return the descriptor
  +     */
  +    private final CLOptionDescriptor getDescriptorFor( final int id )
  +    {
  +        for( int i = 0; i < m_optionDescriptors.length; i++ )
  +        {
  +            if( m_optionDescriptors[ i ].getId() == id )
  +            {
  +                return m_optionDescriptors[ i ];
  +            }
  +        }
  +
  +        return null;
  +    }
  +
  +    /**
  +     * Retrieve a descriptor by name.
  +     *
  +     * @param name the name
  +     * @return the descriptor
  +     */
  +    private final CLOptionDescriptor getDescriptorFor( final String name )
  +    {
  +        for( int i = 0; i < m_optionDescriptors.length; i++ )
  +        {
  +            if( m_optionDescriptors[ i ].getName().equals( name ) )
  +            {
  +                return m_optionDescriptors[ i ];
  +            }
  +        }
  +
  +        return null;
  +    }
  +
  +    /**
  +     * Retrieve an error message that occured during parsing if one existed.
  +     *
  +     * @return the error string
  +     */
  +    public final String getErrorString()
  +    {
  +        //System.out.println( "ErrorString: " + m_errorMessage );
  +        return m_errorMessage;
  +    }
  +
  +    /**
  +     * Require state to be placed in for option.
  +     *
  +     * @param descriptor the Option Descriptor
  +     * @return the state
  +     */
  +    private final int getStateFor( final CLOptionDescriptor descriptor )
  +    {
  +        final 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;
  +        }
  +    }
  +
  +    /**
  +     * Create a parser that can deal with options and parses certain args.
  +     *
  +     * @param args the args, typically that passed to the
  +     * <code>public static void main(String[] args)</code> method.
  +     * @param optionDescriptors the option descriptors
  +     * @param control the parser control used determine behaviour of parser
  +     */
  +    public CLArgsParser( final String[] args,
  +                         final CLOptionDescriptor[] optionDescriptors,
  +                         final ParserControl control )
  +    {
  +        m_optionDescriptors = optionDescriptors;
  +        m_control = control;
  +        m_options = new Vector();
  +        m_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 ) );
  +    }
  +
  +    /**
  +     * Check for duplicates of an option.
  +     * It is an error to have duplicates unless appropriate flags is set in descriptor.
  +     *
  +     * @param arguments the arguments
  +     */
  +    private final void checkIncompatibilities( final Vector arguments )
  +        throws ParseException
  +    {
  +        final int size = arguments.size();
  +
  +        for( int i = 0; i < size; i++ )
  +        {
  +            final CLOption option = (CLOption)arguments.elementAt( i );
  +            final int id = option.getDescriptor().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 void checkIncompatible( final Vector arguments,
  +                                          final int[] incompatible,
  +                                          final int original )
  +        throws ParseException
  +    {
  +        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.getDescriptor().getId();
  +
  +            for( int j = 0; j < incompatible.length; j++ )
  +            {
  +                if( id == incompatible[ j ] )
  +                {
  +                    final CLOption originalOption = (CLOption)arguments.elementAt( original );
  +                    final int originalId = originalOption.getDescriptor().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 String describeDualOption( final 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();
  +        }
  +    }
  +
  +    /**
  +     * Create a parser that deals with options and parses certain args.
  +     *
  +     * @param args the args
  +     * @param optionDescriptors the option descriptors
  +     */
  +    public CLArgsParser( final String[] args,
  +                         final CLOptionDescriptor[] optionDescriptors )
  +    {
  +        this( args, optionDescriptors, null );
  +    }
  +
  +    /**
  +     * 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
  +     */
  +    private final String[] subArray( final String[] array,
  +                                     final int index,
  +                                     final int charIndex )
  +    {
  +        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;
  +    }
  +
  +    /**
  +     * Actually parse arguments
  +     */
  +    private final void parse()
  +        throws ParseException
  +    {
  +        if( 0 == m_args.length )
  +        {
  +            return;
  +        }
  +
  +        m_stringLength = m_args[ m_argIndex ].length();
  +
  +        //ch = peekAtChar();
  +
  +        while( true )
  +        {
  +            m_ch = peekAtChar();
  +
  +            //System.out.println( "Pre State=" + m_state );
  +            //System.out.println( "Pre Char=" + (char)ch + "/" + (int)ch );
  +
  +            if( m_argIndex >= m_args.length )
  +            {
  +                break;
  +            }
  +
  +            if( null != m_control && m_control.isFinished( m_lastOptionId ) )
  +            {
  +                //this may need mangling due to peeks
  +                m_unparsedArgs = subArray( m_args, m_argIndex, m_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 == m_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( m_args[ m_argIndex++ ] ) );
  +            }
  +            else if( STATE_OPTIONAL_ARG == m_state && '-' == m_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.getDescriptor().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.getDescriptor().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 String getOptionDescription( final CLOptionDescriptor descriptor )
  +    {
  +        if( m_isLong )
  +        {
  +            return "--" + descriptor.getName();
  +        }
  +        else
  +        {
  +            return "-" + (char)descriptor.getId();
  +        }
  +    }
  +
  +    private final char peekAtChar()
  +    {
  +        if( INVALID == m_lastChar )
  +        {
  +            m_lastChar = readChar();
  +        }
  +        return (char)m_lastChar;
  +    }
  +
  +    private final char getChar()
  +    {
  +        if( INVALID != m_lastChar )
  +        {
  +            final char result = (char)m_lastChar;
  +            m_lastChar = INVALID;
  +            return result;
  +        }
  +        else
  +        {
  +            return readChar();
  +        }
  +    }
  +
  +    private final char readChar()
  +    {
  +        if( m_stringIndex >= m_stringLength )
  +        {
  +            m_argIndex++;
  +            m_stringIndex = 0;
  +
  +            if( m_argIndex < m_args.length )
  +            {
  +                m_stringLength = m_args[ m_argIndex ].length();
  +            }
  +            else
  +            {
  +                m_stringLength = 0;
  +            }
  +
  +            return 0;
  +        }
  +
  +        if( m_argIndex >= m_args.length )
  +        {
  +            return 0;
  +        }
  +
  +        return m_args[ m_argIndex ].charAt( m_stringIndex++ );
  +    }
  +
  +    private final Token nextToken( final char[] separators )
  +    {
  +        m_ch = getChar();
  +
  +        if( isSeparator( m_ch, separators ) )
  +        {
  +            m_ch = getChar();
  +            return new Token( TOKEN_SEPARATOR, null );
  +        }
  +
  +        final StringBuffer sb = new StringBuffer();
  +
  +        do
  +        {
  +            sb.append( m_ch );
  +            m_ch = getChar();
  +        } while( !isSeparator( m_ch, separators ) );
  +
  +        return new Token( TOKEN_STRING, sb.toString() );
  +    }
  +
  +    private final boolean isSeparator( final char ch, final char[] separators )
  +    {
  +        for( int i = 0; i < separators.length; i++ )
  +        {
  +            if( ch == separators[ i ] )
  +            {
  +                return true;
  +            }
  +        }
  +
  +        return false;
  +    }
  +
  +    private final void addOption( final CLOption option )
  +    {
  +        m_options.addElement( option );
  +        m_lastOptionId = option.getDescriptor().getId();
  +        m_option = null;
  +    }
  +
  +    private final void parseOption( final CLOptionDescriptor descriptor,
  +                                    final String optionString )
  +        throws ParseException
  +    {
  +        if( null == descriptor )
  +        {
  +            throw new ParseException( "Unknown option " + optionString, 0 );
  +        }
  +
  +        m_state = getStateFor( descriptor );
  +        m_option = new CLOption( descriptor );
  +
  +        if( STATE_NORMAL == m_state )
  +        {
  +            addOption( m_option );
  +        }
  +    }
  +
  +    private final void parseShortOption()
  +        throws ParseException
  +    {
  +        m_ch = getChar();
  +        final CLOptionDescriptor descriptor = getDescriptorFor( m_ch );
  +        m_isLong = false;
  +        parseOption( descriptor, "-" + m_ch );
  +
  +        if( STATE_NORMAL == m_state )
  +        {
  +            m_state = STATE_OPTION_MODE;
  +        }
  +    }
  +
  +    private final void parseArguments()
  +        throws ParseException
  +    {
  +        if( STATE_REQUIRE_ARG == m_state )
  +        {
  +            if( '=' == m_ch || 0 == m_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( '-' == m_ch || 0 == m_ch )
  +            {
  +                getChar(); //consume stray character
  +                addOption( m_option );
  +                m_state = STATE_NORMAL;
  +                return;
  +            }
  +
  +            if( '=' == m_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.getDescriptor().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();
  +
  +                m_ch = getChar();
  +                if( '-' == m_ch )
  +                {
  +                    m_lastChar = m_ch;
  +                }
  +
  +                while( !isSeparator( m_ch, ARG2_SEPARATORS ) )
  +                {
  +                    sb.append( m_ch );
  +                    m_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;
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Parse Options from Normal mode.
  +     */
  +    private final void parseNormal()
  +        throws ParseException
  +    {
  +        if( '-' != m_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
  +            {
  +                m_ch = peekAtChar();
  +
  +                //if it is a short option then parse it else ...
  +                if( '-' != m_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 );
  +                        m_isLong = true;
  +                        parseOption( descriptor, "--" + optionName );
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Build the m_optionIndex lookup map for the parsed options.
  +     */
  +    private final void buildOptionIndex()
  +    {
  +        final int size = m_options.size();
  +        m_optionIndex = new Hashtable( size * 2 );
  +
  +        for( int i = 0; i < size; i++ )
  +        {
  +            final CLOption option = (CLOption)m_options.get( i );
  +            final CLOptionDescriptor optionDescriptor =
  +                getDescriptorFor( option.getDescriptor().getId() );
  +
  +            m_optionIndex.put( new Integer( option.getDescriptor().getId() ), option );
  +
  +            if( null != optionDescriptor &&
  +                null != optionDescriptor.getName() )
  +            {
  +                m_optionIndex.put( optionDescriptor.getName(), option );
  +            }
  +        }
  +    }
  +}
  
  
  
  1.5       +14 -4     avalon-excalibur/compatibility/src/java/org/apache/avalon/excalibur/cli/CLOption.java
  
  Index: CLOption.java
  ===================================================================
  RCS file: /home/cvs/avalon-excalibur/compatibility/src/java/org/apache/avalon/excalibur/cli/CLOption.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- CLOption.java	22 Mar 2003 12:46:22 -0000	1.4
  +++ CLOption.java	24 Mar 2003 09:03:32 -0000	1.5
  @@ -55,6 +55,7 @@
    * Basic class describing an instance of option.
    *
    * @author <a href="mailto:peter at apache.org">Peter Donald</a>
  + * @author <a href="mailto:leo.sutic at inspireinfrastructure.com">Leo Sutic</a>
    * @version $Revision$ $Date$
    * @since 4.0
    */
  @@ -65,8 +66,14 @@
        */
       public static final int TEXT_ARGUMENT = 0;
   
  +    /**
  +     * Default descriptor. Required, since code assumes that getDescriptor will never return null.
  +     */
  +    private static final CLOptionDescriptor TEXT_ARGUMENT_DESCRIPTOR = 
  +        new CLOptionDescriptor( null, CLOptionDescriptor.ARGUMENT_OPTIONAL, TEXT_ARGUMENT, null );
  +    
       private String[] m_arguments;
  -    private CLOptionDescriptor m_descriptor;
  +    private CLOptionDescriptor m_descriptor = TEXT_ARGUMENT_DESCRIPTOR;
   
       /**
        * Retrieve argument to option if it takes arguments.
  @@ -118,11 +125,14 @@
       /**
        * Constructor taking an descriptor
        *
  -     * @param descriptor the descriptor
  +     * @param descriptor the descriptor iff null, will default to a "text argument" descriptor.
        */
       public CLOption( final CLOptionDescriptor descriptor )
       {
  -        m_descriptor = descriptor;
  +        if( descriptor != null )
  +        {
  +            m_descriptor = descriptor;
  +        }
       }
   
       /**
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org


Mime
View raw message