1 16 package org.apache.axis.utils; 19 20 import java.text.ParseException ; 21 import java.util.Hashtable ; 22 import java.util.Vector ; 23 24 35 public final class CLArgsParser 36 { 37 private static final int STATE_NORMAL = 0; 38 private static final int STATE_REQUIRE_2ARGS = 1; 39 private static final int STATE_REQUIRE_ARG = 2; 40 private static final int STATE_OPTIONAL_ARG = 3; 41 private static final int STATE_NO_OPTIONS = 4; 42 private static final int STATE_OPTION_MODE = 5; 43 44 private static final int TOKEN_SEPARATOR = 0; 45 private static final int TOKEN_STRING = 1; 46 47 48 private static final char[] ARG2_SEPARATORS = 49 new char[] { (char)0, '=', '-' }; 50 51 private static final char[] ARG_SEPARATORS = 52 new char[] { (char)0, '=' }; 53 54 private static final char[] NULL_SEPARATORS = 55 new char[] { (char)0 }; 56 57 private final CLOptionDescriptor[] m_optionDescriptors; 58 private final Vector m_options; 59 private Hashtable m_optionIndex; 60 private final ParserControl m_control; 61 62 private String m_errorMessage; 63 private String [] m_unparsedArgs = new String [] {}; 64 65 private char ch; 67 private String [] args; 68 private boolean isLong; 69 private int argIndex; 70 private int stringIndex; 71 private int stringLength; 72 73 private static final int INVALID = Integer.MAX_VALUE; 75 private int m_lastChar = INVALID; 76 77 private int m_lastOptionId; 78 private CLOption m_option; 79 private int m_state = STATE_NORMAL; 80 81 public final String [] getUnparsedArgs() 82 { 83 return m_unparsedArgs; 84 } 85 86 91 public final Vector getArguments() 92 { 93 return m_options; 95 } 96 97 106 public final CLOption getArgumentById( final int id ) 107 { 108 return (CLOption)m_optionIndex.get( new Integer ( id ) ); 109 } 110 111 120 public final CLOption getArgumentByName( final String name) 121 { 122 return (CLOption)m_optionIndex.get( name ); 123 } 124 125 131 private final CLOptionDescriptor getDescriptorFor( final int id ) 132 { 133 for( int i = 0; i < m_optionDescriptors.length; i++ ) 134 { 135 if( m_optionDescriptors[i].getId() == id ) 136 { 137 return m_optionDescriptors[i]; 138 } 139 } 140 141 return null; 142 } 143 144 150 private final CLOptionDescriptor getDescriptorFor( final String name ) 151 { 152 for( int i = 0; i < m_optionDescriptors.length; i++ ) 153 { 154 if( m_optionDescriptors[i].getName().equals( name ) ) 155 { 156 return m_optionDescriptors[i]; 157 } 158 } 159 160 return null; 161 } 162 163 168 public final String getErrorString() 169 { 170 return m_errorMessage; 172 } 173 174 180 private final int getStateFor( final CLOptionDescriptor descriptor ) 181 { 182 int flags = descriptor.getFlags(); 183 if( ( flags & CLOptionDescriptor.ARGUMENTS_REQUIRED_2 ) == 184 CLOptionDescriptor.ARGUMENTS_REQUIRED_2 ) 185 { 186 return STATE_REQUIRE_2ARGS; 187 } 188 else if( ( flags & CLOptionDescriptor.ARGUMENT_REQUIRED ) == 189 CLOptionDescriptor.ARGUMENT_REQUIRED ) 190 { 191 return STATE_REQUIRE_ARG; 192 } 193 else if( ( flags & CLOptionDescriptor.ARGUMENT_OPTIONAL ) == 194 CLOptionDescriptor.ARGUMENT_OPTIONAL ) 195 { 196 return STATE_OPTIONAL_ARG; 197 } 198 else 199 { 200 return STATE_NORMAL; 201 } 202 } 203 204 211 public CLArgsParser( final String [] args, 212 final CLOptionDescriptor[] optionDescriptors, 213 final ParserControl control ) 214 { 215 m_optionDescriptors = optionDescriptors; 216 m_control = control; 217 m_options = new Vector (); 218 this.args = args; 219 220 try 221 { 222 parse(); 223 checkIncompatibilities( m_options ); 224 buildOptionIndex(); 225 } 226 catch( final ParseException pe ) 227 { 228 m_errorMessage = pe.getMessage(); 229 } 230 231 } 234 235 241 private final void checkIncompatibilities( final Vector arguments ) 242 throws ParseException 243 { 244 final int size = arguments.size(); 245 246 for( int i = 0; i < size; i++ ) 247 { 248 final CLOption option = (CLOption)arguments.elementAt( i ); 249 final int id = option.getId(); 250 final CLOptionDescriptor descriptor = getDescriptorFor( id ); 251 252 if( null == descriptor ) 255 { 256 continue; 257 } 258 259 final int[] incompatible = descriptor.getIncompatible(); 260 261 checkIncompatible( arguments, incompatible, i ); 262 } 263 } 264 265 private final void checkIncompatible( final Vector arguments, 266 final int[] incompatible, 267 final int original ) 268 throws ParseException 269 { 270 final int size = arguments.size(); 271 272 for( int i = 0; i < size; i++ ) 273 { 274 if( original == i ) 275 { 276 continue; 277 } 278 279 final CLOption option = (CLOption)arguments.elementAt( i ); 280 final int id = option.getId(); 281 283 for( int j = 0; j < incompatible.length; j++ ) 284 { 285 if( id == incompatible[ j ] ) 286 { 287 final CLOption originalOption = (CLOption)arguments.elementAt( original ); 288 final int originalId = originalOption.getId(); 289 290 String message = null; 291 292 if( id == originalId ) 293 { 294 message = 295 "Duplicate options for " + describeDualOption( originalId ) + 296 " found."; 297 } 298 else 299 { 300 message = "Incompatible options -" + 301 describeDualOption( id ) + " and " + 302 describeDualOption( originalId ) + " found."; 303 } 304 throw new ParseException ( message, 0 ); 305 } 306 } 307 } 308 } 309 310 private final String describeDualOption( final int id ) 311 { 312 final CLOptionDescriptor descriptor = getDescriptorFor( id ); 313 if( null == descriptor ) 314 { 315 return "<parameter>"; 316 } 317 else 318 { 319 final StringBuffer sb = new StringBuffer (); 320 boolean hasCharOption = false; 321 322 if( Character.isLetter( (char)id ) ) 323 { 324 sb.append( '-' ); 325 sb.append( (char)id ); 326 hasCharOption = true; 327 } 328 329 final String longOption = descriptor.getName(); 330 if( null != longOption ) 331 { 332 if( hasCharOption ) 333 { 334 sb.append( '/' ); 335 } 336 sb.append( "--" ); 337 sb.append( longOption ); 338 } 339 340 return sb.toString(); 341 } 342 } 343 344 350 public CLArgsParser( final String [] args, 351 final CLOptionDescriptor[] optionDescriptors ) 352 { 353 this( args, optionDescriptors, null ); 354 } 355 356 366 private final String [] subArray( final String [] array, 367 final int index, 368 final int charIndex ) 369 { 370 final int remaining = array.length - index; 371 final String [] result = new String [ remaining ]; 372 373 if( remaining > 1 ) 374 { 375 System.arraycopy( array, index + 1, result, 1, remaining - 1 ); 376 } 377 378 result[0] = array[ index ].substring( charIndex - 1 ); 379 380 return result; 381 } 382 383 388 private final void parse() 389 throws ParseException 390 { 391 if( 0 == args.length ) 392 { 393 return; 394 } 395 396 stringLength = args[ argIndex ].length(); 397 398 400 while( true ) 401 { 402 ch = peekAtChar(); 403 404 407 if( argIndex >= args.length ) 408 { 409 break; 410 } 411 412 if( null != m_control && m_control.isFinished( m_lastOptionId ) ) 413 { 414 m_unparsedArgs = subArray( args, argIndex, stringIndex ); 416 return; 417 } 418 419 422 if( STATE_OPTION_MODE == m_state ) 423 { 424 if( 0 == ch ) 427 { 428 getChar(); m_state = STATE_NORMAL; 430 } 431 else 432 { 433 parseShortOption(); 434 } 435 } 436 else if( STATE_NORMAL == m_state ) 437 { 438 parseNormal(); 439 } 440 else if( STATE_NO_OPTIONS == m_state ) 441 { 442 addOption( new CLOption( args[ argIndex++ ] ) ); 444 } 445 else if( STATE_OPTIONAL_ARG == m_state && '-' == ch ) 446 { 447 m_state = STATE_NORMAL; 448 addOption( m_option ); 449 } 450 else 451 { 452 parseArguments(); 453 } 454 } 455 456 if( m_option != null ) 457 { 458 if( STATE_OPTIONAL_ARG == m_state ) 459 { 460 m_options.addElement( m_option ); 461 } 462 else if( STATE_REQUIRE_ARG == m_state ) 463 { 464 final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() ); 465 final String message = 466 "Missing argument to option " + getOptionDescription( descriptor ); 467 throw new ParseException ( message, 0 ); 468 } 469 else if( STATE_REQUIRE_2ARGS == m_state ) 470 { 471 if( 1 == m_option.getArgumentCount() ) 472 { 473 m_option.addArgument( "" ); 474 m_options.addElement( m_option ); 475 } 476 else 477 { 478 final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() ); 479 final String message = 480 "Missing argument to option " + getOptionDescription( descriptor ); 481 throw new ParseException ( message, 0 ); 482 } 483 } 484 else 485 { 486 throw new ParseException ( "IllegalState " + m_state + ": " + m_option, 0 ); 487 } 488 } 489 } 490 491 private final String getOptionDescription( final CLOptionDescriptor descriptor ) 492 { 493 if( isLong ) 494 { 495 return "--" + descriptor.getName(); 496 } 497 else 498 { 499 return "-" + (char)descriptor.getId(); 500 } 501 } 502 503 private final char peekAtChar() 504 { 505 if( INVALID == m_lastChar ) 506 { 507 m_lastChar = readChar(); 508 } 509 return (char)m_lastChar; 510 } 511 512 private final char getChar() 513 { 514 if( INVALID != m_lastChar ) 515 { 516 final char result = (char)m_lastChar; 517 m_lastChar = INVALID; 518 return result; 519 } 520 else 521 { 522 return readChar(); 523 } 524 } 525 526 private final char readChar() 527 { 528 if( stringIndex >= stringLength ) 529 { 530 argIndex++; 531 stringIndex = 0; 532 533 if( argIndex < args.length ) 534 { 535 stringLength = args[ argIndex ].length(); 536 } 537 else 538 { 539 stringLength = 0; 540 } 541 542 return 0; 543 } 544 545 if( argIndex >= args.length ) 546 return 0; 547 548 return args[ argIndex ].charAt( stringIndex++ ); 549 } 550 551 private final Token nextToken( final char[] separators ) 552 { 553 ch = getChar(); 554 555 if( isSeparator( ch, separators ) ) 556 { 557 ch = getChar(); 558 return new Token( TOKEN_SEPARATOR, null ); 559 } 560 561 final StringBuffer sb = new StringBuffer (); 562 563 do 564 { 565 sb.append( ch ); 566 ch = getChar(); 567 } 568 while( !isSeparator( ch, separators ) ); 569 570 return new Token( TOKEN_STRING, sb.toString() ); 571 } 572 573 private final boolean isSeparator( final char ch, final char[] separators ) 574 { 575 for( int i = 0; i < separators.length; i++ ) 576 { 577 if( ch == separators[ i ] ) 578 { 579 return true; 580 } 581 } 582 583 return false; 584 } 585 586 private final void addOption( final CLOption option ) 587 { 588 m_options.addElement( option ); 589 m_lastOptionId = option.getId(); 590 m_option = null; 591 } 592 593 private final void parseOption( final CLOptionDescriptor descriptor, 594 final String optionString ) 595 throws ParseException 596 { 597 if( null == descriptor ) 598 { 599 throw new ParseException ( "Unknown option " + optionString, 0 ); 600 } 601 602 m_state = getStateFor( descriptor ); 603 m_option = new CLOption( descriptor.getId() ); 604 605 if( STATE_NORMAL == m_state ) 606 { 607 addOption( m_option ); 608 } 609 } 610 611 private final void parseShortOption() 612 throws ParseException 613 { 614 ch = getChar(); 615 final CLOptionDescriptor descriptor = getDescriptorFor( ch ); 616 isLong = false; 617 parseOption( descriptor, "-" + ch ); 618 619 if( STATE_NORMAL == m_state ) 620 { 621 m_state = STATE_OPTION_MODE; 622 } 623 } 624 625 private final void parseArguments() 626 throws ParseException 627 { 628 if( STATE_REQUIRE_ARG == m_state ) 629 { 630 if( '=' == ch || 0 == ch ) 631 { 632 getChar(); 633 } 634 635 final Token token = nextToken( NULL_SEPARATORS ); 636 m_option.addArgument( token.getValue() ); 637 638 addOption( m_option ); 639 m_state = STATE_NORMAL; 640 } 641 else if( STATE_OPTIONAL_ARG == m_state ) 642 { 643 if( '-' == ch || 0 == ch ) 644 { 645 getChar(); addOption( m_option ); 647 m_state = STATE_NORMAL; 648 return; 649 } 650 651 if( '=' == ch ) 652 { 653 getChar(); 654 } 655 656 final Token token = nextToken( NULL_SEPARATORS ); 657 m_option.addArgument( token.getValue() ); 658 659 addOption( m_option ); 660 m_state = STATE_NORMAL; 661 } 662 else if( STATE_REQUIRE_2ARGS == m_state ) 663 { 664 if( 0 == m_option.getArgumentCount() ) 665 { 666 final Token token = nextToken( ARG_SEPARATORS ); 667 668 if( TOKEN_SEPARATOR == token.getType() ) 669 { 670 final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() ); 671 final String message = 672 "Unable to parse first argument for option " + 673 getOptionDescription( descriptor ); 674 throw new ParseException ( message, 0 ); 675 } 676 else 677 { 678 m_option.addArgument( token.getValue() ); 679 } 680 } 681 else { 683 final StringBuffer sb = new StringBuffer (); 684 685 ch = getChar(); 686 if( '-' == ch ) 687 { 688 m_lastChar = ch; 689 } 690 691 while( !isSeparator( ch, ARG2_SEPARATORS ) ) 692 { 693 sb.append( ch ); 694 ch = getChar(); 695 } 696 697 final String argument = sb.toString(); 698 699 701 m_option.addArgument( argument ); 702 addOption( m_option ); 703 m_option = null; 704 m_state = STATE_NORMAL; 705 } 706 } 707 } 708 709 712 private final void parseNormal() 713 throws ParseException 714 { 715 if( '-' != ch ) 716 { 717 final String argument = nextToken( NULL_SEPARATORS ).getValue(); 719 addOption( new CLOption( argument ) ); 720 m_state = STATE_NORMAL; 721 } 722 else 723 { 724 getChar(); 726 if( 0 == peekAtChar() ) 727 { 728 throw new ParseException ( "Malformed option -", 0 ); 729 } 730 else 731 { 732 ch = peekAtChar(); 733 734 if( '-' != ch ) 736 { 737 parseShortOption(); 738 } 739 else 740 { 741 getChar(); 745 if( 0 == peekAtChar() ) 746 { 747 getChar(); 748 m_state = STATE_NO_OPTIONS; 749 } 750 else 751 { 752 final String optionName = nextToken( ARG_SEPARATORS ).getValue(); 754 final CLOptionDescriptor descriptor = getDescriptorFor( optionName ); 755 isLong = true; 756 parseOption( descriptor, "--" + optionName ); 757 } 758 } 759 } 760 } 761 } 762 763 766 private final void buildOptionIndex() 767 { 768 m_optionIndex = new Hashtable ( m_options.size() * 2 ); 769 770 for( int i = 0; i < m_options.size(); i++ ) 771 { 772 final CLOption option = (CLOption)m_options.get( i ); 773 final CLOptionDescriptor optionDescriptor = 774 getDescriptorFor( option.getId() ); 775 776 m_optionIndex.put( new Integer ( option.getId() ), option ); 777 778 if( null != optionDescriptor ) 779 { 780 m_optionIndex.put( optionDescriptor.getName(), option ); 781 } 782 } 783 } 784 } 785 | Popular Tags |