Source for net.dpml.cli.commandline.Parser

   1: /*
   2:  * Copyright 2003-2005 The Apache Software Foundation
   3:  * Copyright 2005 Stephen McConnell
   4:  *
   5:  * Licensed under the Apache License, Version 2.0 (the "License");
   6:  * you may not use this file except in compliance with the License.
   7:  * You may obtain a copy of the License at
   8:  *
   9:  *     http://www.apache.org/licenses/LICENSE-2.0
  10:  *
  11:  * Unless required by applicable law or agreed to in writing, software
  12:  * distributed under the License is distributed on an "AS IS" BASIS,
  13:  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14:  * See the License for the specific language governing permissions and
  15:  * limitations under the License.
  16:  */
  17: package net.dpml.cli.commandline;
  18: 
  19: import java.io.IOException;
  20: 
  21: import java.util.LinkedList;
  22: import java.util.List;
  23: import java.util.ListIterator;
  24: 
  25: import net.dpml.cli.CommandLine;
  26: import net.dpml.cli.Group;
  27: import net.dpml.cli.Option;
  28: import net.dpml.cli.OptionException;
  29: import net.dpml.cli.WriteableCommandLine;
  30: import net.dpml.cli.resource.ResourceConstants;
  31: import net.dpml.cli.util.HelpFormatter;
  32: 
  33: /**
  34:  * A class that implements the <code>Parser</code> interface can parse a
  35:  * String array according to the {@link Group}specified and return a
  36:  * {@link CommandLine}.
  37:  *
  38:  * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
  39:  * @version @PROJECT-VERSION@
  40:  */
  41: public class Parser
  42: {
  43:     private HelpFormatter m_helpFormatter = new HelpFormatter();
  44:     private Option m_helpOption = null;
  45:     private String m_helpTrigger = null;
  46:     private Group m_group = null;
  47: 
  48:     /**
  49:      * Parse the arguments according to the specified options and properties.
  50:      *
  51:      * @param arguments the command line arguments
  52:      * @return the list of atomic option and value tokens
  53:      * @throws OptionException if there are any problems encountered while parsing the
  54:      *   command line tokens.
  55:      */
  56:     public CommandLine parse( final String[] arguments ) throws OptionException
  57:     {
  58:         // build a mutable list for the arguments
  59:         final List argumentList = new LinkedList();
  60: 
  61:         // copy the arguments into the new list
  62:         for( int i = 0; i < arguments.length; i++ )
  63:         {
  64:             final String argument = arguments[i];
  65: 
  66:             // ensure non intern'd strings are used 
  67:             // so that == comparisons work as expected
  68:             argumentList.add( new String( argument ) );
  69:         }
  70: 
  71:         // wet up a command line for this group
  72:         final WriteableCommandLine commandLine = 
  73:           new WriteableCommandLineImpl( m_group, argumentList );
  74: 
  75:         // pick up any defaults from the model
  76:         m_group.defaults( commandLine );
  77: 
  78:         // process the options as far as possible
  79:         final ListIterator iterator = argumentList.listIterator();
  80:         Object previous = null;
  81:         
  82:         while( m_group.canProcess( commandLine, iterator ) )
  83:         {
  84:             // peek at the next item and backtrack
  85:             final Object next = iterator.next();
  86:             iterator.previous();
  87:             // if we have just tried to process this instance
  88:             if( next == previous )
  89:             {
  90:                 // abort
  91:                 break;
  92:             }
  93:             // remember previous
  94:             previous = next;
  95:             m_group.process( commandLine, iterator );
  96:         }
  97:         
  98:         // if there are more arguments we have a problem
  99:         if( iterator.hasNext() )
 100:         {
 101:             final String arg = (String) iterator.next();
 102:             throw new OptionException(
 103:               m_group, 
 104:               ResourceConstants.UNEXPECTED_TOKEN, 
 105:               arg );
 106:         }
 107:         
 108:         // no need to validate if the help option is present
 109:         if( !commandLine.hasOption( m_helpOption ) && !commandLine.hasOption( m_helpTrigger ) )
 110:         {
 111:             m_group.validate( commandLine );
 112:         }
 113:         return commandLine;
 114:     }
 115: 
 116:     /**
 117:      * Parse the arguments according to the specified options and properties and
 118:      * displays the usage screen if the CommandLine is not valid or the help
 119:      * option was specified.
 120:      *
 121:      * @param arguments the command line arguments
 122:      * @return a valid CommandLine or null if the parse was unsuccessful
 123:      * @throws IOException if an error occurs while formatting help
 124:      */
 125:     public CommandLine parseAndHelp( final String[] arguments ) throws IOException
 126:     {
 127:         m_helpFormatter.setGroup( m_group );
 128: 
 129:         try
 130:         {
 131:             // attempt to parse the command line
 132:             final CommandLine commandLine = parse( arguments );
 133:             if( !commandLine.hasOption( m_helpOption ) && !commandLine.hasOption( m_helpTrigger ) )
 134:             {
 135:                 return commandLine;
 136:             }
 137:         } 
 138:         catch( final OptionException oe )
 139:         {
 140:             // display help regarding the exception
 141:             m_helpFormatter.setException( oe );
 142:         }
 143: 
 144:         // print help
 145:         m_helpFormatter.print();
 146:         return null;
 147:     }
 148: 
 149:     /**
 150:      * Sets the Group of options to parse against
 151:      * @param group the group of options to parse against
 152:      */
 153:     public void setGroup( final Group group )
 154:     {
 155:         m_group = group;
 156:     }
 157: 
 158:     /**
 159:      * Sets the HelpFormatter to use with the simplified parsing.
 160:      * @see #parseAndHelp(String[])
 161:      * @param helpFormatter the HelpFormatter to use with the simplified parsing
 162:      */
 163:     public void setHelpFormatter( final HelpFormatter helpFormatter )
 164:     {
 165:         m_helpFormatter = helpFormatter;
 166:     }
 167: 
 168:     /**
 169:      * Sets the help option to use with the simplified parsing.  For example
 170:      * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used.
 171:      * @see #parseAndHelp(String[])
 172:      * @param helpOption the help Option
 173:      */
 174:     public void setHelpOption( final Option helpOption )
 175:     {
 176:         m_helpOption = helpOption;
 177:     }
 178: 
 179:     /**
 180:      * Sets the help option to use with the simplified parsing.  For example
 181:      * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used.
 182:      * @see #parseAndHelp(String[])
 183:      * @param helpTrigger the trigger of the help Option
 184:      */
 185:     public void setHelpTrigger( final String helpTrigger )
 186:     {
 187:         m_helpTrigger = helpTrigger;
 188:     }
 189: }