| /******************************************************************************* |
| * Copyright (c) 2001, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.command.internal.env.commandline; |
| |
| import java.text.MessageFormat; |
| import java.util.Arrays; |
| import java.util.BitSet; |
| import java.util.ResourceBundle; |
| import java.util.Vector; |
| import org.eclipse.wst.command.internal.env.common.StringUtils; |
| |
| |
| /** |
| * <p>This is a generic command line parsing class. The programmer need only specify |
| * the characteristics of their command line(ie. positional parameters, flags, etc) |
| * and this class will perform the rest of the parsing work. As an added bonus this |
| * class will also create formated help text that displays the syntax of this |
| * command line. |
| * |
| * <p>The main parameter to the CommandLine constructor is a two dimensional String |
| * array. There are 5 columns in this array and as many rows as needed for each |
| * flag or positional parameter. The five columns are: |
| * |
| * <ol> |
| * <li>The name of the flag(eg. "help" or "a", etc) |
| * Note: no dash should be in the name here. The user would specify "-help" on the |
| * command line though. |
| * <li>The name of the flag parameter(if any) |
| * <li>A string indicating whether this flag can appear more than once on the |
| * command line. |
| * <li>A string indicating whether this flag must be specified on the command line. |
| * <li>A help text string which describes this particular flag or positional parameter. |
| * </ol> |
| * |
| * <p>Each row in the string array is associate with either a positional parameter |
| * or with a flag. For example, consider this command line: |
| * <ul> |
| * <li>My_prog required_parm1 -ab parm_for_ab required_parm2 -help optional_parms |
| * </ul> |
| * |
| * <p>In this example My_prog is the name of the program. required_parm1 and |
| * required_parm2 must be specified on the command line. Notice that they do not |
| * have to be adjacent to each other on the command line. optional_parms may optionally |
| * specified. optional_parms can be 0 or more parameters. They does not need to be |
| * adjacent to the required parameters, but they do need to follow the required |
| * parameters. Two flags are specified "-ab" and "-help". The "-ab" flag has a |
| * parameter "parm_for_ab" associated with it. Note: a flag can not have an optional |
| * parameter. (ie. a flag either never have a parameter or it always has a parameter) |
| * In this example, the first two rows in the string array would describe required_parm1 |
| * and required_parm2. The third entry would describe optional_parms. The fourth and |
| * fifth rows would describe "-ab" and "-help". For this command line the string array |
| * would look like this: |
| * |
| * <ul> |
| * <li>{ { CommandLine.POSITIONAL, "parm1", CommandLine.NO_DUPS, |
| * CommandLine.REQUIRED, "parm1 help text" }, |
| * <li>{ CommandLine.POSITIONAL, "parm2", CommandLine.NO_DUPS, |
| * CommandLine.REQUIRED, "parm2 help text" }, |
| * <li>{ CommandLine.POSITIONAL, "optional_parms", CommandLine.DUPS_OK, |
| * CommandLine.REQUIRED, "optional help text" }, |
| * <li>{ "ab", "parm_for_ab", CommandLine.NO_DUPS, |
| * CommandLine.OPTIONAL, "ab help text" }, |
| * <li>{ "help", CommandLine.NO_PARM, CommandLine.NO_DUPS, |
| * CommandLine.OPTIONAL, "displays this help text" } } |
| * </ul> |
| * |
| * <p>String array rules: |
| * |
| * <ol> |
| * <li>Positional rows must always come first in the array. These rows must |
| * have a name specified in column 2, except for one case. If you want to indicate that |
| * there are no optional positional parameters you would put CommandLine.NO_PARM |
| * in column 2 of the positional row. You would also need to put CommandLine.OPTIONAL |
| * in column 4 since this row is for optional parameters(or the non-existence of |
| * optional parameters as the case may be) |
| * <li>Once a positional row specifies that it is optional, no further positional rows |
| * may be specified. |
| * <li>At least one positional row must be specified, even if it is to just to specify that |
| * there are no optional parameters. |
| * <li>Flag names must be in lower case. Note: the user can specify upper or lower case |
| * on the command line. |
| * <li>If a flag has a parameter the name of the parameter should be put into column 2. |
| * otherwise CommandLine.NO_PARM should be put in column 2. |
| * <li>If a flag is allowed to appear more than once on the command line then |
| * CommandLine.DUPS_OK should be put into column 3, otherwise CommandLine.NO_DUPS |
| * should be put into column 3. |
| * <li>If a flag must be specified on the command line then CommandLine.REQUIRED should |
| * be specified in column 4, otherwise CommandLine.OPTIONAL should be specified. |
| * <li>A help flag must be specified. |
| * <li>The strings specified in the flags column, the parameter name column, and the |
| * help column are always translated using the resource bundle specified. Of |
| * course the special string values such as POSITIONAL and NO_PARM are not |
| * translated. |
| * </ol> |
| * |
| * <p> Flag matching rules: |
| * <ol> |
| * <li>The parser will attempt to match a user specified flag with the minimum number |
| * of programmer specified flag characters. For example, if the programmer has |
| * specified that the flag is "help" the user could specify "-h", "-he", "-hel", or |
| * "-help". If the programmer has also specified a flag called "hello", the |
| * user would get an error message for specifing either "-h", "-he" or "-hel", since |
| * it is ambiguous which flag is being refered to. Both "-hell" and "-hello" |
| * would be ok for the user to specify the hello flag on the command line. |
| * <li>If a flag has a parameter, the parameter may be immediately adjacent to the flag. |
| * For example if "abcd" is specified as a flag with a parameter, the user could |
| * specify the following assuming there are no other ambiguous flags. "-abcdparm", |
| * "-abcparm", "-abparm", or "-aparm" where parm is the parameter for the flag. |
| * (Of course the user can always put a white space between the flag and the |
| * parameter.) |
| * <li>If a flag does not have a parameter and a parameter is adjacent to it then this |
| * parameter is interpreted as a positional parameter. For example if "abcb" is |
| * specified as a flag and the user specifies "-abhello", then the first "ab" will be |
| * interpreted as the flag and "hello" will be interpreted as a positional |
| * parameter. |
| * </ol> |
| * |
| * @author Peter Moogk |
| * @date July 13, 2000 |
| **/ |
| |
| public class CommandLine |
| { |
| // Constant strings that the user should use in their flags_info input array. |
| /** |
| * Specifies that this flag or positional parameter is required. |
| **/ |
| public static final String REQUIRED = "required"; |
| /** |
| * Specifies that this flag or positional parameter is optional. |
| **/ |
| public static final String OPTIONAL = "optional"; |
| /** |
| * Specifies that this flag may be specified more than once on the command line. |
| * Note: This string has no meaning for positional parameters. |
| **/ |
| public static final String DUPS_OK = "dups_ok"; |
| /** |
| * Specifies that this flag may not be specified more than once on the command line. |
| * Note: This string has no meaning for positional parameters. |
| **/ |
| public static final String NO_DUPS = "no_dups"; |
| /** |
| * Specifies that a row is a positional parameter row. |
| **/ |
| public static final String POSITIONAL = ""; |
| /** |
| * Specifies that a flag has no parameter. For positional parameters this |
| * string indicates that there are no optional parameters. |
| **/ |
| public static final String NO_PARM = ""; |
| |
| /** |
| * @param flags_info This parameter specifies the characteristics of the |
| * command line parser. See the class description for a |
| * definition of what this string array should look like. |
| * @param help_flag This string indicates which flag in the flags_info |
| * array is the help flag. |
| * @param tool_name This string indicates the name of the tool that this |
| * command line parser is being used for. This string |
| * is only used when creating the help text. |
| **/ |
| public CommandLine( String[][] flags_info, |
| String help_flag, |
| String tool_name, |
| ResourceBundle flagMessages ) |
| |
| throws InternalErrorExc |
| { |
| this.flags_info = flags_info; |
| this.help_flag = help_flag; |
| this.tool_name = tool_name; |
| this.flagMessages = flagMessages; |
| |
| messages = ResourceBundle.getBundle( "org.eclipse.wst.command.internal.env.commandline.commandline" ); |
| verify_flags_info(); |
| } |
| |
| /** |
| * Call this method to parse a command line. |
| * @param args This is the string array from the command line. |
| * @throws Flag_error If the user has specified the command line incorrectly |
| * a Flag_error exception will be thrown. Use getMessage |
| * to get a description of the user error. |
| * |
| * @throws Help_specified If the user specifies the help flag this exception |
| * will be thrown. Use getMessage to get a fully |
| * formatted syntax description of this command line. |
| **/ |
| public void check_flags( String[] args ) throws Flag_error |
| { |
| flags_specified = new Vector[flags_info.length]; |
| |
| for( int index = 0; index < args.length; index++ ) |
| { |
| boolean processed_the_next_arg = process_arg( args, index ); |
| if( processed_the_next_arg == true ) index++; |
| } |
| |
| // If help was specified we will not check the regular rules. |
| if( !flag_specified( help_flag ) ) |
| { |
| // Check for flags breaking the rules specified in flags_info. |
| check_rules(); |
| |
| // Call subclassed method to see if more processing is required. |
| more_processing(); |
| } |
| } |
| |
| /** |
| * This method is for subclasses of this class. This method is called at |
| * the very end of check_flags method. It is intended that subclasses would |
| * perform additional command line checking here. |
| **/ |
| protected void more_processing() throws Flag_error, InternalErrorExc |
| { |
| } |
| |
| /** |
| * Once the command line has been parsed by calling check_flags a |
| * call can be made to this method to get the parameters for this flag. |
| * If the flag was not specified on the command line null will be returned. |
| * If the flag was specified, but has no parameters a valid vector will be |
| * returned containing a null. |
| **/ |
| public String[] get_flag_parms( String flag ) |
| { |
| int row = 0; |
| boolean flag_found = false; |
| |
| while( flag_found == false && row < flags_info.length ) |
| { |
| if( flags_info[row][FLAG_COL].equals( flag ) ) |
| { |
| flag_found = true; |
| } |
| else |
| { |
| row++; |
| } |
| } |
| |
| if( flag_found == true ) |
| { |
| Vector parms = flags_specified[row]; |
| return parms == null ? null : (String[])(parms.toArray( new String[0] )); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Call this method to get all of the positional parameters. |
| * This method returns both the required positionals and the |
| * optional positionals in that order. If no positional parameters |
| * were specified null will be returned. |
| **/ |
| public String[] get_positionals() |
| { |
| return (String[])flags_specified[POSITIONAL_ROW].toArray( new String[0] ); |
| } |
| |
| /** |
| * This method returns true if this flag was specified by the user |
| * otherwise false is returned. |
| **/ |
| public boolean flag_specified( String flag ) |
| { |
| return get_flag_parms( flag ) != null; |
| } |
| |
| /** |
| * This method returns fully formated help text syntax for this |
| * command line. |
| **/ |
| public String get_help_text() |
| { |
| StringBuffer help_text = new StringBuffer(400); |
| int help_width = HELP_LINE_LEN - |
| 2 - // blanks |
| 1 - // dash |
| max_flag_size - // flag field |
| 1 - // blank |
| max_name_size - // name field |
| 1; // blank |
| |
| help_text.append( messages.getString( FlagMessages.PARSER_INFO_SYNTAX ) + |
| ": " + tool_name + " " ); |
| |
| // Display the required positionals if any. |
| for( int index = 0; index < required_positionals; index++ ) |
| { |
| help_text.append( flagMessages.getString( flags_info[index][NAME_COL] ) + |
| " " ); |
| } |
| |
| help_text.append( "[" + messages.getString( FlagMessages.PARSER_FLAGS ) + |
| "] " ); |
| |
| if( optional_positionals_allowed == true ) |
| { |
| help_text.append( flagMessages.getString( flags_info[optional_list_index][NAME_COL] ) ); |
| } |
| |
| help_text.append( "\n " + messages.getString( FlagMessages.PARSER_INFO_WHERE ) + "\n" ); |
| |
| // Create one line of description for each parameter |
| for( int row = 0; row < flags_info.length; row++ ) |
| { |
| String columnId = flags_info[row][NAME_COL]; |
| String columnName = columnId == NO_PARM ? "" : flagMessages.getString( columnId ); |
| |
| String flagId = flags_info[row][FLAG_COL]; |
| String flagName = flagId == POSITIONAL ? POSITIONAL : flagMessages.getString(flagId); |
| |
| int flag_padding = max_flag_size - flagName.length(); |
| int name_padding = max_name_size - columnName.length(); |
| |
| // Skip this row if this is a marker for no optional positionals. |
| if( flags_info[row][FLAG_COL] == POSITIONAL && |
| flags_info[row][NAME_COL] == NO_PARM ) continue; |
| |
| if( flagName == POSITIONAL ) |
| { |
| help_text.append( getBlanks(3 ) ); |
| } |
| else |
| { |
| help_text.append( " -" + flagName ); |
| } |
| |
| help_text.append( getBlanks( flag_padding + 1 ) ); |
| help_text.append( columnName ); |
| help_text.append( getBlanks( name_padding + 1 ) ); |
| |
| String columnHelp = flagMessages.getString( flags_info[row][HELP_COL] ); |
| String[] split_help_text |
| = StringUtils.splitter( columnHelp, help_width ); |
| |
| if( split_help_text.length > 0 ) |
| help_text.append( split_help_text[0] + "\n" ); |
| else |
| help_text.append( "\n" ); |
| |
| for( int index = 1; index < split_help_text.length; index++ ) |
| { |
| help_text.append( getBlanks( HELP_LINE_LEN - help_width ) ); |
| help_text.append( split_help_text[index] + "\n" ); |
| } |
| |
| help_text.append( "\n" ); |
| } |
| |
| return "" + help_text; |
| } |
| |
| /** |
| * Return a string with the specified number of blanks. |
| */ |
| private String getBlanks( int count ) |
| { |
| char[] blanks = new char[count]; |
| Arrays.fill( blanks, 0, count, ' ' ); |
| |
| return new String( blanks ); |
| } |
| |
| /** |
| * This class is the base for all command line exception classes. |
| **/ |
| static public class ErrorExc extends Exception |
| { |
| /** |
| * Comment for <code>serialVersionUID</code> |
| */ |
| private static final long serialVersionUID = 3257567317259793720L; |
| |
| public ErrorExc( String message, String[] args ) |
| { |
| super( MessageFormat.format( message, args ) ); |
| } |
| } |
| |
| /** |
| * This class will be thrown when an internal error is detected. |
| * This usually happens if the flag description information was |
| * specified incorrectly. |
| **/ |
| static public class InternalErrorExc extends IllegalArgumentException |
| { |
| /** |
| * Comment for <code>serialVersionUID</code> |
| */ |
| private static final long serialVersionUID = 3258410621136614450L; |
| |
| public InternalErrorExc( String message, String[] args ) |
| { |
| super( MessageFormat.format( message, args ) ); |
| } |
| |
| public InternalErrorExc( String message ) |
| { |
| this( message, (String[])null ); |
| } |
| |
| public InternalErrorExc( String message, String arg ) |
| { |
| this( message, new String[]{ arg } ); |
| } |
| } |
| |
| /** |
| * This class will be thrown if a user error occurs while parsing the command line. |
| **/ |
| static public class Flag_error extends ErrorExc |
| { |
| /** |
| * Comment for <code>serialVersionUID</code> |
| */ |
| private static final long serialVersionUID = 3832621776877663537L; |
| |
| public Flag_error( String message, String[] args ) |
| { |
| super( message, args ); |
| } |
| |
| public Flag_error( String message, String arg ) |
| { |
| super( message, new String[]{ arg } ); |
| } |
| |
| public Flag_error( String message ) |
| { |
| super( message, null ); |
| } |
| } |
| |
| /** |
| * Tries to process a single flag on the command line. |
| * @param args All the command line parameters. |
| * @param arg_index This is the index of the argument that is to be processed. |
| * @return returns true if the argument we are processing is a flag that has a |
| * parameter and the parameter is specified in the next argument. |
| **/ |
| private boolean process_arg( String[] args, int arg_index ) throws Flag_error |
| { |
| boolean processed_next_arg = false; |
| |
| if( args[arg_index].charAt(0) == '-' ) |
| { |
| // This is the start of a flag. |
| int flag_index = 1; |
| int info_index = get_info_index( args[arg_index], flag_index ); |
| int max_index = get_max_index( args[arg_index], flag_index, info_index ); |
| |
| if( flags_info[info_index][NAME_COL] != NO_PARM ) |
| { |
| // This flag takes a parameter so check if it is stuck to this |
| // arg. |
| if( max_index < args[arg_index].length() ) |
| { |
| add_flag_parm( info_index, |
| args[arg_index].substring( max_index, |
| args[arg_index].length() ) ); |
| } |
| else |
| { |
| // This flag has a parameter and it wasn't stuck to the flag, |
| // so we will try to get it from the next arg. |
| if( arg_index+1 < args.length && |
| args[arg_index+1].charAt(0) != '-' ) |
| { |
| // We found an parameter in the next string so we will use this |
| // one as a parameter for this flag. Note: if was no parameter |
| // after the flag at all, the error will be caught in the |
| // check_rules method. |
| add_flag_parm( info_index, args[arg_index+1] ); |
| processed_next_arg = true; |
| } |
| else |
| { |
| // Error missing paramater. This error is caught by check_rules. |
| add_flag_parm( info_index, null ); |
| } |
| } |
| } |
| else |
| { |
| // The flag does not have a parameter so we will add a null. |
| add_flag_parm( info_index, null ); |
| |
| // Check to see if a positional parameter is stuck to this flag. |
| if( max_index < args[arg_index].length() ) |
| { |
| add_positional( args[arg_index].substring( max_index, |
| args[arg_index].length() ) ); |
| } |
| } |
| } |
| else |
| { |
| // This is a positional parameter. |
| add_positional( args[arg_index] ); |
| } |
| |
| return processed_next_arg; |
| } |
| |
| /** |
| * Finds the row for the flag that uniquely matched this flag str. |
| * @return returns the flags_info index of the matching flag. |
| **/ |
| private int get_info_index( String flag_str, int start_index ) |
| throws Flag_error |
| { |
| //int info_start = 1; |
| //int info_end = flags_info.length; |
| int info_index; |
| int found_count = 0; |
| int info_col_index = 0; |
| int last_info_index = 0; |
| |
| BitSet flags_rejected = new BitSet(); |
| |
| // Loop over each char in flag_str. Note: we will probably bail early. |
| for( int flag_col_index = start_index; flag_col_index < flag_str.length(); flag_col_index++ ) |
| { |
| // Loop over each flag in flag_info |
| for( info_index = 0; info_index < flags_info.length; info_index++ ) |
| { |
| String flagId = flags_info[info_index][FLAG_COL]; |
| String flagName = flagId == POSITIONAL ? POSITIONAL : flagMessages.getString( flagId ); |
| |
| if( flags_rejected.get( info_index ) == false && |
| info_col_index < flagName.length() && |
| Character.toLowerCase(flag_str.charAt(flag_col_index)) == |
| flagName.charAt(info_col_index) ) |
| { |
| found_count++; |
| last_info_index = info_index; |
| } |
| else |
| { |
| flags_rejected.set( info_index ); |
| } |
| } |
| |
| if( found_count == 1 ) |
| { |
| // We have a match. |
| return last_info_index; |
| } |
| else if( found_count == 0 ) |
| { |
| // Flag not found at all. |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_FLAG_NOT_FOUND ), |
| flag_str.substring( start_index ) ); |
| } |
| else |
| { |
| // More than one flag was found with this char so we will go to the |
| // next char to uniquely match it. |
| info_col_index++; |
| //info_start = last_info_index - found_count + 1; |
| //info_end = last_info_index + 1; |
| found_count = 0; |
| } |
| } |
| |
| // The only way to get to this code is if the loop exited with |
| // the found_count greater than 1. Therefore, the flag specified is |
| // ambiguous. |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_AMBIGUOUS_FLAG ), |
| flag_str.substring( start_index) ); |
| } |
| |
| /** |
| * This method tries to match as many characters as possible of the user |
| * specified flag with the matched flag string. |
| * @return returns the position of the last matching flag chararacter. |
| **/ |
| private int get_max_index( String flag_str, int flag_start, int info_index ) |
| { |
| int flag_col_index = flag_start; |
| int info_col_index = 0; |
| |
| String info_str = flagMessages.getString( flags_info[info_index][FLAG_COL] ); |
| |
| while( flag_col_index < flag_str.length() && |
| info_col_index < info_str.length() ) |
| { |
| if( Character.toLowerCase( flag_str.charAt(flag_col_index) ) != |
| info_str.charAt(info_col_index) ) |
| break; |
| |
| flag_col_index++; |
| info_col_index++; |
| } |
| |
| return flag_col_index; |
| } |
| |
| /** |
| * Adds a positional parameter to flags_specified. |
| **/ |
| private void add_positional( String positional_parm ) |
| { |
| if( flags_specified[POSITIONAL_ROW] == null ) |
| flags_specified[POSITIONAL_ROW] = new Vector(3); |
| |
| flags_specified[POSITIONAL_ROW].add( positional_parm ); |
| } |
| |
| /** |
| * Adds a flag and its parameter to flags_specified. If only the |
| * flag was specified, then a null should be passed to flag_parm. |
| **/ |
| private void add_flag_parm( int flag_index, String flag_parm ) |
| throws Flag_error |
| { |
| if( flags_info[flag_index][DUP_COL] == NO_DUPS && |
| flags_specified[flag_index] != null ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_DUPLICATE_FLAGS_NOT_ALLOWED ), |
| flagMessages.getString( flags_info[flag_index][FLAG_COL] ) ); |
| |
| if( flags_specified[flag_index] == null ) |
| flags_specified[flag_index] = new Vector(3); |
| |
| flags_specified[flag_index].add( flag_parm ); |
| } |
| |
| /** |
| * Checks that the user hasn't broken any command line rules. |
| **/ |
| private void check_rules() throws Flag_error |
| { |
| // Check that all of the required positionals were specified. |
| int positional_count = 0; |
| |
| if( flags_specified[POSITIONAL_ROW] != null ) |
| { |
| positional_count = flags_specified[POSITIONAL_ROW].size(); |
| } |
| |
| if( required_positionals > positional_count ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_MISSING_POSITIONAL ), |
| flagMessages.getString( flags_info[required_positionals-1][NAME_COL] ) ); |
| |
| else if( required_positionals < positional_count && |
| optional_positionals_allowed == false ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_TOO_MANY_POSITIONALS ) ); |
| |
| for( int row = 0; row < flags_info.length; row++ ) |
| { |
| if( flags_info[row][FLAG_COL] == POSITIONAL ) continue; |
| |
| if( flags_specified[row] == null && |
| flags_info[row][REQUIRED_COL] == REQUIRED ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_MISSING_REQUIRED_FLAG ), |
| flagMessages.getString( flags_info[row][FLAG_COL] ) ); |
| |
| int parm_count = 0; |
| |
| if( flags_specified[row] != null ) parm_count = flags_specified[row].size(); |
| |
| // Check for too many flag parameters. |
| if( flags_info[row][DUP_COL] == NO_DUPS && parm_count > 1 ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_DUPLICATE_FLAGS_NOT_ALLOWED ), |
| flagMessages.getString( flags_info[row][FLAG_COL] ) ); |
| |
| // Check for missing flag parameter. |
| if( parm_count > 0 && flags_info[row][NAME_COL] != NO_PARM ) |
| { |
| for( int index = 0; index < flags_specified[row].size(); index++ ) |
| { |
| if( flags_specified[row].elementAt(index) == null ) |
| throw new Flag_error( messages.getString( FlagMessages.PARSER_ERROR_MISSING_FLAG_PARAMETER ), |
| new String[] |
| { flagMessages.getString( flags_info[row][FLAG_COL] ), |
| flagMessages.getString( flags_info[row][NAME_COL] ) } ); |
| |
| } |
| } |
| } |
| } |
| |
| /** |
| * This method verifies that a proper flags_info string array was passed |
| * to us by the programmer. |
| **/ |
| private void verify_flags_info() throws InternalErrorExc |
| { |
| boolean done_positionals = false; |
| boolean help_specified = false; |
| |
| required_positionals = 0; |
| optional_positionals_allowed = false; |
| optional_list_index = -1; |
| max_flag_size = 0; |
| max_name_size = 0; |
| |
| if( flags_info == null || flags_info.length == 0 ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_NO_FLAGS_DATA_SPECIFIED ) ); |
| |
| if( flags_info[POSITIONAL_ROW] != null && |
| flags_info[POSITIONAL_ROW].length > 0 && |
| flags_info[POSITIONAL_ROW][FLAG_COL] != POSITIONAL ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_FIRST_FLAG_NOT_POSITIONAL ) ); |
| |
| for( int row = 0; row < flags_info.length; row++ ) |
| { |
| if( flags_info[row] == null ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_NULL_FLAG_ROW ) ); |
| |
| if( flags_info[row].length != 5 ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_INCORRECT_ROW_SIZE ) ); |
| |
| if( flags_info[row][FLAG_COL] == null || |
| flags_info[row][NAME_COL] == null || |
| flags_info[row][HELP_COL] == null ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_NULL_IN_ROW ) ); |
| |
| if( flags_info[row][FLAG_COL].equals( help_flag ) ) help_specified = true; |
| |
| String flagId = flags_info[row][FLAG_COL]; |
| String nameId = flags_info[row][NAME_COL]; |
| |
| String flag_col = flagId == POSITIONAL ? POSITIONAL : flagMessages.getString( flagId ); |
| String name_col = nameId == NO_PARM ? NO_PARM : flagMessages.getString( nameId ); |
| |
| if( flag_col.length() > max_flag_size ) |
| max_flag_size = flag_col.length(); |
| |
| if( name_col != NO_PARM && name_col.length() > max_name_size ) |
| max_name_size = name_col.length(); |
| |
| // Ensure that flags are all in lowercase. |
| if( !flag_col.equals( flag_col.toLowerCase() ) ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_FLAG_NOT_LOWERCASE ), |
| flag_col ); |
| |
| // Ensure that only the predefined dup strings are used. |
| // Note: it's ok to use != when comparing constant strings literals. |
| if( flags_info[row][DUP_COL] == null || |
| ( flags_info[row][DUP_COL] != NO_DUPS && |
| flags_info[row][DUP_COL] != DUPS_OK ) ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_INCORRECT_DUP_STRING ), |
| flags_info[row][DUP_COL] ); |
| |
| // Ensure that only the predefined required strings are used. |
| if( flags_info[row][REQUIRED_COL] == null || |
| ( flags_info[row][REQUIRED_COL] != REQUIRED && |
| flags_info[row][REQUIRED_COL] != OPTIONAL ) ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_INCORRECT_REQUIRED_STRING ), |
| flags_info[row][REQUIRED_COL] ); |
| |
| // Count the number of required positionals. |
| if( flags_info[row][FLAG_COL] == POSITIONAL ) |
| { |
| if( flags_info[row][REQUIRED_COL] == REQUIRED ) |
| { |
| if( flags_info[row][NAME_COL] == NO_PARM ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_REQUIRED_POSITIONAL_NEEDS_NAME ) ); |
| |
| required_positionals++; |
| } |
| else if( flags_info[row][NAME_COL] != NO_PARM ) |
| { |
| // We use the NAME_COL field for an optional positional to denote |
| // whether additional positionals are allowed or not. |
| optional_positionals_allowed = true; |
| optional_list_index = row; |
| } |
| } |
| |
| // Ensure that positionals are at the beginning of the info. |
| if( flags_info[row][FLAG_COL] != POSITIONAL || |
| ( done_positionals == false && |
| flags_info[row][FLAG_COL] == POSITIONAL && |
| flags_info[row][REQUIRED_COL] == OPTIONAL ) ) |
| { |
| done_positionals = true; |
| } |
| else if( done_positionals == true ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_POSITIONAL_NOT_AT_BEGINNING ) ); |
| } |
| |
| // Ensure that a help flag was specified in the info list. |
| if( help_specified == false ) |
| throw new InternalErrorExc( messages.getString( FlagMessages.PARSER_ERROR_HELP_FLAG_NOT_SPECIFIED ) ); |
| } |
| |
| /** |
| * This method is used to dump internal information about a parsed |
| * command line. |
| **/ |
| public String toString() |
| { |
| StringBuffer b = new StringBuffer(100); |
| |
| for( int row = 0; row < flags_info.length; row++ ) |
| { |
| b.append( "\n" ); |
| |
| if( flags_info[row][FLAG_COL] == POSITIONAL ) |
| b.append( "Positional:" ); |
| else |
| b.append( flagMessages.getString( flags_info[row][FLAG_COL] ) + ":" ); |
| |
| |
| if( flags_specified[row] == null ) |
| b.append( "no parameters" ); |
| else |
| for( int parm_index = 0; parm_index < flags_specified[row].size(); parm_index++ ) |
| { |
| String parm = (String)flags_specified[row].elementAt(parm_index); |
| b.append( parm + ":" ); |
| } |
| b.append( "\n" ); |
| } |
| |
| return ""+b; |
| } |
| |
| private static final int FLAG_COL = 0; |
| private static final int NAME_COL = 1; |
| private static final int DUP_COL = 2; |
| private static final int REQUIRED_COL = 3; |
| private static final int HELP_COL = 4; |
| |
| private static final int POSITIONAL_ROW = 0; |
| private static final int HELP_LINE_LEN = 75; |
| |
| private String[][] flags_info; |
| private String help_flag; |
| private String tool_name; |
| private Vector[] flags_specified; |
| private int required_positionals; |
| private boolean optional_positionals_allowed; |
| private int optional_list_index; |
| private int max_flag_size; |
| private int max_name_size; |
| |
| protected ResourceBundle messages; |
| private ResourceBundle flagMessages; |
| } |