1 23 24 29 30 31 32 package com.sun.cli.jmx.support; 33 34 import java.lang.reflect.Array ; 35 import java.util.ArrayList ; 36 37 38 39 public final class ArgParserImpl implements ArgParser 40 { 41 public static class ParseChars 42 { 43 public final static ParseChars DEFAULT = new ParseChars(); 44 45 public char mArgDelim; 46 47 public char mEscapeChar; 48 public String mEscapableChars; 49 public String mEscapableCharsWithinLiteralString; 50 public char mArrayLeft; 51 public char mArrayRight; 52 53 final static char TYPECAST_BEGIN = '('; 55 final static char TYPECAST_END = ')'; 56 final static char LITERAL_STRING_DELIM = '\"'; 57 final static char ARG_VALUE_DELIM = '='; 58 59 public void 60 validate() 61 { 62 assert( mEscapableChars.indexOf( mEscapeChar ) >= 0 ); 64 assert( mEscapableChars.indexOf( DEFAULT_ARRAY_LEFT ) >= 0 ); 65 66 assert( mEscapableChars.indexOf( '(' ) >= 0 ); 68 } 69 70 public 71 ParseChars() 72 { 73 mArgDelim = DEFAULT_ARG_DELIM; 74 mEscapeChar = DEFAULT_ESCAPE_CHAR; 75 mEscapableChars = DEFAULT_ESCAPABLE_CHARS; 76 mEscapableCharsWithinLiteralString = DEFAULT_ESCAPABLE_CHARS_WITHIN_LITERAL_STRING; 77 mArrayLeft = DEFAULT_ARRAY_LEFT; 78 mArrayRight = DEFAULT_ARRAY_RIGHT; 79 80 validate(); 81 } 82 }; 83 84 85 boolean mNamedArgs = false; 86 String mInput; 87 int mCurIndex; 88 ParseChars mParseChars; 89 90 91 public 92 ArgParserImpl( ) 93 { 94 mParseChars = ParseChars.DEFAULT; 95 } 96 97 public 98 ArgParserImpl( final ParseChars parseChars ) 99 { 100 mParseChars = parseChars; 101 } 102 103 104 private int 105 inputRemainingCount() 106 { 107 return( mInput.length() - mCurIndex ); 108 } 109 110 private static boolean 111 isDigit( int theChar ) 112 { 113 return( (theChar >= '0' && theChar <= '9') ); 114 } 115 116 private static boolean 117 isHexDigit( int theChar ) 118 { 119 return( isDigit( theChar ) || (theChar >= 'a' && theChar <= 'f') || 120 (theChar >= 'A' && theChar <= 'F') ); 121 } 122 123 private boolean 124 IsEscapableChar( int theChar, String escapableChars ) 125 { 126 return( escapableChars.indexOf( theChar ) >= 0 || theChar == mParseChars.mEscapeChar ); 127 } 128 129 private int 130 escapeCharToChar( int theChar ) 131 { 132 int result = -1; 133 134 if ( theChar == 'n' ) 135 result = '\n'; 136 else if ( theChar == 'r' ) 137 result = '\r'; 138 else if ( theChar == 't' ) 139 result = '\t'; 140 else 141 result = theChar; 142 143 return( result ); 144 } 145 146 147 152 private int 153 nextChar( int escapeChar, String escapableChars ) 154 { 155 int result = -1; 156 157 final int theChar = nextLiteralChar(); 158 if ( theChar == escapeChar ) 159 { 160 final int theNextChar = nextLiteralChar(); 161 if ( IsEscapableChar( theNextChar, escapableChars ) ) 162 { 163 result = escapeCharToChar( theNextChar ); 164 } 165 else 166 { 167 result = escapeChar; 171 if ( isHexDigit( theNextChar ) && peekNextLiteralChar() > 0 ) 172 { 173 final int theNextNextChar = nextLiteralChar(); 174 if ( isHexDigit( theNextNextChar ) ) 175 { 176 result = (((int)theNextChar) << 4) + (int)theNextNextChar; 177 } 178 } 179 else 180 { 181 backup( 1 ); 182 } 183 } 184 } 185 else 186 { 187 result = theChar; 188 } 189 190 return( result ); 191 } 192 193 private int 194 nextChar() 195 { 196 return( nextChar( mParseChars.mEscapeChar, mParseChars.mEscapableChars ) ); 197 } 198 199 private int 200 nextLiteralChar() 201 { 202 final int result = peekNextLiteralChar(); 203 if ( result > 0 ) 204 { 205 advance( 1 ); 206 } 207 208 return( result ); 209 } 210 211 private String 212 peekRemaining() 213 { 214 if ( inputRemainingCount() <= 0 ) 215 return( "" ); 216 217 return( mInput.substring( mCurIndex, mInput.length() ) ); 218 } 219 220 private int 221 peekNextLiteralChar() 222 { 223 if ( inputRemainingCount() <= 0 ) 224 return( -1 ); 225 226 final char result = mInput.charAt( mCurIndex ); 227 228 return( result ); 229 } 230 231 private void 232 backup( int count ) 233 { 234 assert( count <= mCurIndex ); 235 236 mCurIndex -= count; 237 } 238 239 private void 240 advance( int count ) 241 { 242 assert( count <= inputRemainingCount() ); 243 244 mCurIndex += count; 245 } 246 247 private void 248 checkInputAvailable() 249 throws ArgParserException 250 { 251 if ( inputRemainingCount() == 0 ) 252 { 253 throw new ArgParserException( "expecting additional input" ); 254 } 255 } 256 257 258 266 private String 267 ParseNamedArgName() 268 throws ArgParserException 269 { 270 checkInputAvailable(); 271 272 final StringBuffer buf = new StringBuffer (); 273 274 boolean foundDelim = false; 275 276 int theChar = 0; 277 while ( (theChar = nextLiteralChar()) > 0 ) 278 { 279 if ( theChar == mParseChars.ARG_VALUE_DELIM ) 280 { 281 foundDelim = true; 282 break; 283 } 284 285 if ( ! Character.isJavaIdentifierPart( (char)theChar ) ) 286 { 287 break; 288 } 289 290 buf.append( (char)theChar ); 291 } 292 293 if ( ! foundDelim ) 294 { 295 throw new ArgParserException( 296 "named arguments must be of the form name=value: " + buf.toString() ); 297 } 298 299 return( new String ( buf ) ); 300 } 301 302 308 private ParseResult 309 ParseNamedArg() 310 throws ArgParserException 311 { 312 checkInputAvailable(); 313 314 final String name = ParseNamedArgName(); 315 316 ParseResult result = null; 317 318 if ( inputRemainingCount() > 0 ) 320 { 321 result = ParseNonNamedArg( "" + mParseChars.mArgDelim ); 322 } 323 else 324 { 325 result = new ParseResult( ParseResult.OTHER, ""); 326 } 327 result.setName( name ); 328 329 return( result ); 330 } 331 332 boolean 333 isStringTypecast( String typecast ) 334 { 335 return( typecast != null && 336 (typecast.equals( "String" ) || typecast.equals( "java.lang.String" ) ) ); 337 } 338 339 344 private ParseResult 345 ParseNonNamedArg( String delimiters ) 346 throws ArgParserException 347 { 348 ParseResult result = null; 349 350 String typeCast = ParseTypeCast(); 352 if ( isStringTypecast( typeCast ) ) 353 { 354 if ( inputRemainingCount() == 0 ) 355 { 356 result = new ParseResult( ParseResult.LITERAL_STRING, "" ); 358 result.setTypeCast( typeCast ); 359 return( result ); 360 } 361 } 362 363 boolean quotedString = false; 364 365 result = ParseLiteralString(); 366 if ( result != null ) 367 { 368 typeCast = "String"; 370 quotedString = true; 371 } 372 else 373 { 374 result = ParseArray(); 375 if ( result == null ) 376 { 377 result = ParseRegular( delimiters ); 378 } 379 } 380 381 result.setTypeCast( typeCast ); 382 if ( isStringTypecast( typeCast ) && result.getType() != ParseResult.ARRAY ) 383 { 384 result.setType( ParseResult.LITERAL_STRING ); 385 386 if ( (! quotedString) && 387 result.getData() instanceof String && 388 "null".equalsIgnoreCase( (String )result.getData() ) ) 389 { 390 result.setData( null ); 391 } 392 } 393 394 final int theChar = nextLiteralChar(); 396 397 boolean validDelimiter = delimiters.indexOf( theChar ) >= 0 || theChar < 0; 398 if ( ! validDelimiter ) 399 { 400 throw new ArgParserException( "Syntax error: parsed this so far: " + mInput.substring( 1, mCurIndex ) ); 401 } 402 403 return( result ); 404 } 405 406 407 413 private String 414 ParseTypeCast( ) 415 throws ArgParserException 416 { 417 int theChar = nextLiteralChar(); 418 if ( theChar != mParseChars.TYPECAST_BEGIN ) 419 { 420 backup( 1 ); 421 return( null ); 422 } 423 424 final StringBuffer buf = new StringBuffer (); 425 426 theChar = nextLiteralChar(); 427 if ( ! Character.isJavaIdentifierStart( (char)theChar ) ) 428 { 429 final String msg = "type cast must contain a legal Java " + 430 "identifier start character: " + peekRemaining(); 431 throw new ArgParserException( msg ); 432 } 433 buf.append( (char)theChar ); 434 435 boolean foundDelim = false; 436 while ( (theChar = nextLiteralChar( )) > 0 ) 437 { 438 if ( theChar == mParseChars.TYPECAST_END ) 439 { 440 foundDelim = true; 441 break; 442 } 443 444 if ( theChar != '.' && ! Character.isJavaIdentifierPart( (char)theChar ) ) 445 { 446 throw new ArgParserException( "type cast must contain a legal Java identifier part: " + 447 (char)theChar ); 448 } 449 450 buf.append( (char)theChar ); 451 } 452 453 if ( ! foundDelim ) 454 { 455 throw new ArgParserException( "type cast must be terminated by the ) character" ); 456 } 457 458 final String result = new String ( buf ); 459 460 if ( result.length() == 0 ) 461 { 462 throw new ArgParserException( "type cast must contain a type" ); 463 } 464 465 return( result ); 466 } 467 468 469 478 private ParseResult 479 ParseRegular( String delimiters ) 480 throws ArgParserException 481 { 482 checkInputAvailable(); 483 484 final StringBuffer buf = new StringBuffer (); 485 486 int theChar; 487 while ( (theChar = peekNextLiteralChar() ) > 0 ) 488 { 489 if ( delimiters.indexOf( theChar ) >= 0 ) 490 { 491 break; 492 } 493 494 theChar = nextChar(); 495 496 buf.append( (char)theChar ); 497 } 498 499 final String resultString = new String ( buf ); 500 501 final ParseResult result = new ParseResult( ParseResult.OTHER, resultString ); 502 503 return( result ); 504 505 } 506 507 508 514 private ParseResult 515 ParseArray( ) 516 throws ArgParserException 517 { 518 checkInputAvailable(); 519 520 int theChar = nextLiteralChar(); 522 if ( theChar != mParseChars.mArrayLeft ) 523 { 524 backup( 1 ); 525 return( null ); 526 } 527 528 final ArrayList elems = new ArrayList (); 529 530 boolean endOfArrayFound = false; 531 532 if ( peekNextLiteralChar() == mParseChars.mArrayRight ) 533 { 534 endOfArrayFound = true; 536 advance( 1 ); 537 } 538 else 539 { 540 while ( (theChar = peekNextLiteralChar( )) > 0 ) 541 { 542 final ParseResult elem = ParseNonNamedArg( "" + 543 mParseChars.mArrayRight + mParseChars.mArgDelim ); 544 elems.add( elem ); 545 546 backup( 1 ); 547 if ( nextLiteralChar() == mParseChars.mArrayRight) 548 { 549 endOfArrayFound = true; 550 break; 551 } 552 } 553 } 554 555 if ( ! endOfArrayFound ) 556 { 557 throw new ArgParserException( "end of array not found" ); 558 } 559 560 final ParseResult [] resultsArray = new ParseResult[ elems.size() ]; 561 elems.toArray( resultsArray ); 562 563 final ParseResult result = new ParseResult( ParseResult.ARRAY, resultsArray ); 564 565 return( result ); 566 567 } 568 569 570 577 private ParseResult 578 ParseLiteralString( ) 579 throws ArgParserException 580 { 581 checkInputAvailable(); 582 583 int theChar = nextLiteralChar(); 585 if ( theChar != mParseChars.LITERAL_STRING_DELIM ) 586 { 587 backup( 1 ); 588 return( null ); 589 } 590 591 final StringBuffer buf = new StringBuffer (); 592 593 boolean endOfStringFound = false; 594 while ( (theChar = peekNextLiteralChar( )) > 0 ) 595 { 596 if ( theChar == mParseChars.LITERAL_STRING_DELIM ) 597 { 598 endOfStringFound = true; 599 advance( 1 ); 600 break; 601 } 602 603 theChar = nextChar( mParseChars.mEscapeChar, mParseChars.mEscapableCharsWithinLiteralString ); 604 buf.append( (char)theChar ); 605 } 606 607 if ( ! endOfStringFound ) 608 { 609 throw new ArgParserException( "literal string must be terminated by double quote \"" ); 610 } 611 612 613 final String resultString = new String ( buf ); 614 615 final ParseResult result = new ParseResult( ParseResult.LITERAL_STRING, resultString ); 616 617 return( result ); 618 } 619 620 625 private ParseResult 626 ParseArg() 627 throws ArgParserException 628 { 629 630 checkInputAvailable(); 631 632 ParseResult result = null; 633 634 if ( mNamedArgs ) 635 { 636 result = ParseNamedArg(); 637 } 638 else 639 { 640 result = ParseNonNamedArg( "" + mParseChars.mArgDelim ); 641 } 642 643 return( result ); 644 } 645 646 647 public String [] 648 ParseNames( String input ) 649 throws ArgParserException 650 { 651 mInput = input; 652 mCurIndex = 0; 653 654 final ArrayList list = new ArrayList (); 655 656 StringBuffer buf = new StringBuffer (); 657 while ( true ) 658 { 659 final int theChar = nextLiteralChar(); 660 661 if ( theChar < 0 || theChar == mParseChars.mArgDelim ) 662 { 663 list.add( new String ( buf ) ); 664 buf.setLength( 0 ); 665 666 if ( theChar < 0 ) 667 break; 668 } 669 else 670 { 671 buf.append( (char)theChar ); 672 } 673 } 674 675 676 final String [] results = (String [])list.toArray( new String [ list.size() ]); 677 678 return( results ); 679 } 680 681 682 public ParseResult [] 683 Parse( String input, boolean namedArgs ) 684 throws ArgParserException 685 { 686 mNamedArgs = namedArgs; 687 mInput = input; 688 mCurIndex = 0; 689 690 final ArrayList results = new ArrayList (); 691 692 while ( inputRemainingCount() > 0 ) 693 { 694 final ParseResult nextArg = ParseArg( ); 695 assert( nextArg != null ); 696 697 results.add( nextArg ); 698 } 699 700 701 final ParseResult [] arrayResults = new ParseResult [ results.size( ) ]; 702 results.toArray( arrayResults ); 703 704 return( arrayResults ); 705 } 706 707 private static void 708 p( Object o ) 709 { 710 System.out.println( o.toString() ); 711 } 712 } 713 714 | Popular Tags |