1 8 package org.jboss.axis.utils; 11 12 import java.text.ParseException ; 13 import java.util.Hashtable ; 14 import java.util.Vector ; 15 16 27 public final class CLArgsParser 28 { 29 private static final int STATE_NORMAL = 0; 30 private static final int STATE_REQUIRE_2ARGS = 1; 31 private static final int STATE_REQUIRE_ARG = 2; 32 private static final int STATE_OPTIONAL_ARG = 3; 33 private static final int STATE_NO_OPTIONS = 4; 34 private static final int STATE_OPTION_MODE = 5; 35 36 private static final int TOKEN_SEPARATOR = 0; 37 private static final int TOKEN_STRING = 1; 38 39 40 private static final char[] ARG2_SEPARATORS = 41 new char[]{(char)0, '=', '-'}; 42 43 private static final char[] ARG_SEPARATORS = 44 new char[]{(char)0, '='}; 45 46 private static final char[] NULL_SEPARATORS = 47 new char[]{(char)0}; 48 49 private final CLOptionDescriptor[] m_optionDescriptors; 50 private final Vector m_options; 51 private Hashtable m_optionIndex; 52 private final ParserControl m_control; 53 54 private String m_errorMessage; 55 private String [] m_unparsedArgs = new String []{}; 56 57 private char ch; 59 private String [] args; 60 private boolean isLong; 61 private int argIndex; 62 private int stringIndex; 63 private int stringLength; 64 65 private static final int INVALID = Integer.MAX_VALUE; 67 private int m_lastChar = INVALID; 68 69 private int m_lastOptionId; 70 private CLOption m_option; 71 private int m_state = STATE_NORMAL; 72 73 public final String [] getUnparsedArgs() 74 { 75 return m_unparsedArgs; 76 } 77 78 83 public final Vector getArguments() 84 { 85 return m_options; 87 } 88 89 98 public final CLOption getArgumentById(final int id) 99 { 100 return (CLOption)m_optionIndex.get(new Integer (id)); 101 } 102 103 112 public final CLOption getArgumentByName(final String name) 113 { 114 return (CLOption)m_optionIndex.get(name); 115 } 116 117 123 private final CLOptionDescriptor getDescriptorFor(final int id) 124 { 125 for (int i = 0; i < m_optionDescriptors.length; i++) 126 { 127 if (m_optionDescriptors[i].getId() == id) 128 { 129 return m_optionDescriptors[i]; 130 } 131 } 132 133 return null; 134 } 135 136 142 private final CLOptionDescriptor getDescriptorFor(final String name) 143 { 144 for (int i = 0; i < m_optionDescriptors.length; i++) 145 { 146 if (m_optionDescriptors[i].getName().equals(name)) 147 { 148 return m_optionDescriptors[i]; 149 } 150 } 151 152 return null; 153 } 154 155 160 public final String getErrorString() 161 { 162 return m_errorMessage; 164 } 165 166 172 private final int getStateFor(final CLOptionDescriptor descriptor) 173 { 174 int flags = descriptor.getFlags(); 175 if ((flags & CLOptionDescriptor.ARGUMENTS_REQUIRED_2) == 176 CLOptionDescriptor.ARGUMENTS_REQUIRED_2) 177 { 178 return STATE_REQUIRE_2ARGS; 179 } 180 else if ((flags & CLOptionDescriptor.ARGUMENT_REQUIRED) == 181 CLOptionDescriptor.ARGUMENT_REQUIRED) 182 { 183 return STATE_REQUIRE_ARG; 184 } 185 else if ((flags & CLOptionDescriptor.ARGUMENT_OPTIONAL) == 186 CLOptionDescriptor.ARGUMENT_OPTIONAL) 187 { 188 return STATE_OPTIONAL_ARG; 189 } 190 else 191 { 192 return STATE_NORMAL; 193 } 194 } 195 196 203 public CLArgsParser(final String [] args, 204 final CLOptionDescriptor[] optionDescriptors, 205 final ParserControl control) 206 { 207 m_optionDescriptors = optionDescriptors; 208 m_control = control; 209 m_options = new Vector (); 210 this.args = args; 211 212 try 213 { 214 parse(); 215 checkIncompatibilities(m_options); 216 buildOptionIndex(); 217 } 218 catch (final ParseException pe) 219 { 220 m_errorMessage = pe.getMessage(); 221 } 222 223 } 226 227 233 private final void checkIncompatibilities(final Vector arguments) 234 throws ParseException 235 { 236 final int size = arguments.size(); 237 238 for (int i = 0; i < size; i++) 239 { 240 final CLOption option = (CLOption)arguments.elementAt(i); 241 final int id = option.getId(); 242 final CLOptionDescriptor descriptor = getDescriptorFor(id); 243 244 if (null == descriptor) 247 { 248 continue; 249 } 250 251 final int[] incompatible = descriptor.getIncompatible(); 252 253 checkIncompatible(arguments, incompatible, i); 254 } 255 } 256 257 private final void checkIncompatible(final Vector arguments, 258 final int[] incompatible, 259 final int original) 260 throws ParseException 261 { 262 final int size = arguments.size(); 263 264 for (int i = 0; i < size; i++) 265 { 266 if (original == i) 267 { 268 continue; 269 } 270 271 final CLOption option = (CLOption)arguments.elementAt(i); 272 final int id = option.getId(); 273 275 for (int j = 0; j < incompatible.length; j++) 276 { 277 if (id == incompatible[j]) 278 { 279 final CLOption originalOption = (CLOption)arguments.elementAt(original); 280 final int originalId = originalOption.getId(); 281 282 String message = null; 283 284 if (id == originalId) 285 { 286 message = 287 "Duplicate options for " + describeDualOption(originalId) + 288 " found."; 289 } 290 else 291 { 292 message = "Incompatible options -" + 293 describeDualOption(id) + " and " + 294 describeDualOption(originalId) + " found."; 295 } 296 throw new ParseException (message, 0); 297 } 298 } 299 } 300 } 301 302 private final String describeDualOption(final int id) 303 { 304 final CLOptionDescriptor descriptor = getDescriptorFor(id); 305 if (null == descriptor) 306 { 307 return "<parameter>"; 308 } 309 else 310 { 311 final StringBuffer sb = new StringBuffer (); 312 boolean hasCharOption = false; 313 314 if (Character.isLetter((char)id)) 315 { 316 sb.append('-'); 317 sb.append((char)id); 318 hasCharOption = true; 319 } 320 321 final String longOption = descriptor.getName(); 322 if (null != longOption) 323 { 324 if (hasCharOption) 325 { 326 sb.append('/'); 327 } 328 sb.append("--"); 329 sb.append(longOption); 330 } 331 332 return sb.toString(); 333 } 334 } 335 336 342 public CLArgsParser(final String [] args, 343 final CLOptionDescriptor[] optionDescriptors) 344 { 345 this(args, optionDescriptors, null); 346 } 347 348 358 private final String [] subArray(final String [] array, 359 final int index, 360 final int charIndex) 361 { 362 final int remaining = array.length - index; 363 final String [] result = new String [remaining]; 364 365 if (remaining > 1) 366 { 367 System.arraycopy(array, index + 1, result, 1, remaining - 1); 368 } 369 370 result[0] = array[index].substring(charIndex - 1); 371 372 return result; 373 } 374 375 380 private final void parse() 381 throws ParseException 382 { 383 if (0 == args.length) 384 { 385 return; 386 } 387 388 stringLength = args[argIndex].length(); 389 390 392 while (true) 393 { 394 ch = peekAtChar(); 395 396 399 if (argIndex >= args.length) 400 { 401 break; 402 } 403 404 if (null != m_control && m_control.isFinished(m_lastOptionId)) 405 { 406 m_unparsedArgs = subArray(args, argIndex, stringIndex); 408 return; 409 } 410 411 414 if (STATE_OPTION_MODE == m_state) 415 { 416 if (0 == ch) 419 { 420 getChar(); m_state = STATE_NORMAL; 422 } 423 else 424 { 425 parseShortOption(); 426 } 427 } 428 else if (STATE_NORMAL == m_state) 429 { 430 parseNormal(); 431 } 432 else if (STATE_NO_OPTIONS == m_state) 433 { 434 addOption(new CLOption(args[argIndex++])); 436 } 437 else if (STATE_OPTIONAL_ARG == m_state && '-' == ch) 438 { 439 m_state = STATE_NORMAL; 440 addOption(m_option); 441 } 442 else 443 { 444 parseArguments(); 445 } 446 } 447 448 if (m_option != null) 449 { 450 if (STATE_OPTIONAL_ARG == m_state) 451 { 452 m_options.addElement(m_option); 453 } 454 else if (STATE_REQUIRE_ARG == m_state) 455 { 456 final CLOptionDescriptor descriptor = getDescriptorFor(m_option.getId()); 457 final String message = 458 "Missing argument to option " + getOptionDescription(descriptor); 459 throw new ParseException (message, 0); 460 } 461 else if (STATE_REQUIRE_2ARGS == m_state) 462 { 463 if (1 == m_option.getArgumentCount()) 464 { 465 m_option.addArgument(""); 466 m_options.addElement(m_option); 467 } 468 else 469 { 470 final CLOptionDescriptor descriptor = getDescriptorFor(m_option.getId()); 471 final String message = 472 "Missing argument to option " + getOptionDescription(descriptor); 473 throw new ParseException (message, 0); 474 } 475 } 476 else 477 { 478 throw new ParseException ("IllegalState " + m_state + ": " + m_option, 0); 479 } 480 } 481 } 482 483 private final String getOptionDescription(final CLOptionDescriptor descriptor) 484 { 485 if (isLong) 486 { 487 return "--" + descriptor.getName(); 488 } 489 else 490 { 491 return "-" + (char)descriptor.getId(); 492 } 493 } 494 495 private final char peekAtChar() 496 { 497 if (INVALID == m_lastChar) 498 { 499 m_lastChar = readChar(); 500 } 501 return (char)m_lastChar; 502 } 503 504 private final char getChar() 505 { 506 if (INVALID != m_lastChar) 507 { 508 final char result = (char)m_lastChar; 509 m_lastChar = INVALID; 510 return result; 511 } 512 else 513 { 514 return readChar(); 515 } 516 } 517 518 private final char readChar() 519 { 520 if (stringIndex >= stringLength) 521 { 522 argIndex++; 523 stringIndex = 0; 524 525 if (argIndex < args.length) 526 { 527 stringLength = args[argIndex].length(); 528 } 529 else 530 { 531 stringLength = 0; 532 } 533 534 return 0; 535 } 536 537 if (argIndex >= args.length) 538 return 0; 539 540 return args[argIndex].charAt(stringIndex++); 541 } 542 543 private final Token nextToken(final char[] separators) 544 { 545 ch = getChar(); 546 547 if (isSeparator(ch, separators)) 548 { 549 ch = getChar(); 550 return new Token(TOKEN_SEPARATOR, null); 551 } 552 553 final StringBuffer sb = new StringBuffer (); 554 555 do 556 { 557 sb.append(ch); 558 ch = getChar(); 559 } 560 while (!isSeparator(ch, separators)); 561 562 return new Token(TOKEN_STRING, sb.toString()); 563 } 564 565 private final boolean isSeparator(final char ch, final char[] separators) 566 { 567 for (int i = 0; i < separators.length; i++) 568 { 569 if (ch == separators[i]) 570 { 571 return true; 572 } 573 } 574 575 return false; 576 } 577 578 private final void addOption(final CLOption option) 579 { 580 m_options.addElement(option); 581 m_lastOptionId = option.getId(); 582 m_option = null; 583 } 584 585 private final void parseOption(final CLOptionDescriptor descriptor, 586 final String optionString) 587 throws ParseException 588 { 589 if (null == descriptor) 590 { 591 throw new ParseException ("Unknown option " + optionString, 0); 592 } 593 594 m_state = getStateFor(descriptor); 595 m_option = new CLOption(descriptor.getId()); 596 597 if (STATE_NORMAL == m_state) 598 { 599 addOption(m_option); 600 } 601 } 602 603 private final void parseShortOption() 604 throws ParseException 605 { 606 ch = getChar(); 607 final CLOptionDescriptor descriptor = getDescriptorFor(ch); 608 isLong = false; 609 parseOption(descriptor, "-" + ch); 610 611 if (STATE_NORMAL == m_state) 612 { 613 m_state = STATE_OPTION_MODE; 614 } 615 } 616 617 private final void parseArguments() 618 throws ParseException 619 { 620 if (STATE_REQUIRE_ARG == m_state) 621 { 622 if ('=' == ch || 0 == ch) 623 { 624 getChar(); 625 } 626 627 final Token token = nextToken(NULL_SEPARATORS); 628 m_option.addArgument(token.getValue()); 629 630 addOption(m_option); 631 m_state = STATE_NORMAL; 632 } 633 else if (STATE_OPTIONAL_ARG == m_state) 634 { 635 if ('-' == ch || 0 == ch) 636 { 637 getChar(); addOption(m_option); 639 m_state = STATE_NORMAL; 640 return; 641 } 642 643 if ('=' == ch) 644 { 645 getChar(); 646 } 647 648 final Token token = nextToken(NULL_SEPARATORS); 649 m_option.addArgument(token.getValue()); 650 651 addOption(m_option); 652 m_state = STATE_NORMAL; 653 } 654 else if (STATE_REQUIRE_2ARGS == m_state) 655 { 656 if (0 == m_option.getArgumentCount()) 657 { 658 final Token token = nextToken(ARG_SEPARATORS); 659 660 if (TOKEN_SEPARATOR == token.getType()) 661 { 662 final CLOptionDescriptor descriptor = getDescriptorFor(m_option.getId()); 663 final String message = 664 "Unable to parse first argument for option " + 665 getOptionDescription(descriptor); 666 throw new ParseException (message, 0); 667 } 668 else 669 { 670 m_option.addArgument(token.getValue()); 671 } 672 } 673 else { 675 final StringBuffer sb = new StringBuffer (); 676 677 ch = getChar(); 678 if ('-' == ch) 679 { 680 m_lastChar = ch; 681 } 682 683 while (!isSeparator(ch, ARG2_SEPARATORS)) 684 { 685 sb.append(ch); 686 ch = getChar(); 687 } 688 689 final String argument = sb.toString(); 690 691 693 m_option.addArgument(argument); 694 addOption(m_option); 695 m_option = null; 696 m_state = STATE_NORMAL; 697 } 698 } 699 } 700 701 704 private final void parseNormal() 705 throws ParseException 706 { 707 if ('-' != ch) 708 { 709 final String argument = nextToken(NULL_SEPARATORS).getValue(); 711 addOption(new CLOption(argument)); 712 m_state = STATE_NORMAL; 713 } 714 else 715 { 716 getChar(); 718 if (0 == peekAtChar()) 719 { 720 throw new ParseException ("Malformed option -", 0); 721 } 722 else 723 { 724 ch = peekAtChar(); 725 726 if ('-' != ch) 728 { 729 parseShortOption(); 730 } 731 else 732 { 733 getChar(); 737 if (0 == peekAtChar()) 738 { 739 getChar(); 740 m_state = STATE_NO_OPTIONS; 741 } 742 else 743 { 744 final String optionName = nextToken(ARG_SEPARATORS).getValue(); 746 final CLOptionDescriptor descriptor = getDescriptorFor(optionName); 747 isLong = true; 748 parseOption(descriptor, "--" + optionName); 749 } 750 } 751 } 752 } 753 } 754 755 758 private final void buildOptionIndex() 759 { 760 m_optionIndex = new Hashtable (m_options.size() * 2); 761 762 for (int i = 0; i < m_options.size(); i++) 763 { 764 final CLOption option = (CLOption)m_options.get(i); 765 final CLOptionDescriptor optionDescriptor = 766 getDescriptorFor(option.getId()); 767 768 m_optionIndex.put(new Integer (option.getId()), option); 769 770 if (null != optionDescriptor) 771 { 772 m_optionIndex.put(optionDescriptor.getName(), option); 773 } 774 } 775 } 776 } 777 | Popular Tags |