1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2000 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Copyright (C) 1996 Active Software, Inc. 31 * All rights reserved. 32 * 33 * @(#) ListParser.java 1.16 - last change made 07/25/97 34 */ 35 36 package sunsoft.jws.visual.rt.type; 37 38 import sunsoft.jws.visual.rt.base.Global; 39 40 import java.util.*; 41 42 /** 43 * Utility class for parsing lists of things in the style of Tcl. 44 * 45 * @version 1.16, 07/25/97 46 */ 47 public class ListParser { 48 49 // Character constants 50 private static final char CHAR_a = /* NOI18N */ 'a'; 51 private static final char CHAR_b = /* NOI18N */ 'b'; 52 private static final char CHAR_f = /* NOI18N */ 'f'; 53 private static final char CHAR_n = /* NOI18N */ 'n'; 54 private static final char CHAR_r = /* NOI18N */ 'r'; 55 private static final char CHAR_t = /* NOI18N */ 't'; 56 private static final char CHAR_x = /* NOI18N */ 'x'; 57 private static final char CHAR_A = /* NOI18N */ 'A'; 58 private static final char CHAR_F = /* NOI18N */ 'F'; 59 private static final char BACKSLASH = /* NOI18N */ '\\'; 60 private static final char BACKSPACE = /* NOI18N */ '\b'; 61 private static final char DQUOTE = /* NOI18N */ '"'; 62 private static final char EQUALS = /* NOI18N */ '='; 63 private static final char FORMFEED = /* NOI18N */ '\f'; 64 private static final char LBRACE = /* NOI18N */ '{'; 65 private static final char NEWLINE = /* NOI18N */ '\n'; 66 private static final char NINE = /* NOI18N */ '9'; 67 private static final char NULL = /* NOI18N */ '\0'; 68 private static final char RBRACE = /* NOI18N */ '}'; 69 private static final char RETURN = /* NOI18N */ '\r'; 70 private static final char SPACE = /* NOI18N */ ' '; 71 private static final char TAB = /* NOI18N */ '\t'; 72 private static final char ZERO = /* NOI18N */ '0'; 73 74 private Vector list; 75 ListParser(String str)76 public ListParser(String str) { 77 int begin = 0; 78 int end = str.length(); 79 initList(str, begin, end); 80 } 81 ListParser(String str, int offset)82 public ListParser(String str, int offset) { 83 int begin, end = str.length(); 84 if (offset >= 0 && offset < end) 85 begin = offset; 86 else 87 begin = end; 88 89 initList(str, begin, end); 90 } 91 ListParser(String str, int begin, int end)92 public ListParser(String str, int begin, int end) { 93 int len = str.length(); 94 if (end < 0 || end > len) 95 end = len; 96 if (begin < 0) 97 begin = 0; 98 if (begin > end) 99 begin = end; 100 101 initList(str, begin, end); 102 } 103 elements()104 public Enumeration elements() { 105 return list.elements(); 106 } 107 size()108 public int size() { 109 return list.size(); 110 } 111 initList(String str, int begin, int end)112 private void initList(String str, int begin, int end) { 113 list = new Vector(); 114 115 int len = end-begin; 116 char buf[] = new char[len]; 117 str.getChars(begin, end, buf, 0); 118 119 parseList(list, buf); 120 } 121 parseList(Vector list, char buf[])122 private void parseList(Vector list, char buf[]) { 123 nextIndex = 0; 124 125 while (nextIndex < buf.length && buf[nextIndex] != 0) { 126 try { 127 findElement(buf, nextIndex); 128 } 129 catch (ParseException ex) { 130 list.removeAllElements(); 131 throw ex; 132 } 133 134 if (elementSize != 0 || 135 (elementIndex < buf.length && buf[elementIndex] != 0)) { 136 if (brace) { 137 list.addElement(new String(buf, elementIndex, 138 elementSize)); 139 } else { 140 list.addElement(collapse(buf, elementIndex, 141 elementSize)); 142 } 143 } 144 } 145 } 146 147 /* BEGIN JSTYLED */ 148 /* 149 *---------------------------------------------------------------------- 150 * 151 * findElement -- 152 * 153 * Given a character buffer containing a Tcl list, locate the first 154 * (or next) element in the list. 155 * 156 * Results: 157 * None. 158 * 159 * Side effects: 160 * If an exception is not thrown, then elementIndex will be set to 161 * the position of the first element of the list, 162 * and nextIndex will 163 * be set to the position of the character just after 164 * any white space 165 * following the last character that's part of the element. If this 166 * is the last argument in the list, then nextIndex will point to the 167 * NULL character at the end of list. elementSize is set to 168 * the number of characters in the element. If the element is in 169 * braces, then elementIndex will point to the character after the 170 * opening brace and elementSize will not include either of the braces. 171 * If there isn't an element in the list, elementSize will be zero, 172 * elementIndex will refer to the null character at the end of list, 173 * and brace will be set to true. 174 * 175 * Note: this procedure does NOT collapse backslash sequences. 176 * 177 *---------------------------------------------------------------------- 178 */ 179 180 /* END JSTYLED */ 181 // Side effect variables 182 private int elementIndex; 183 private int nextIndex; 184 private int elementSize; 185 private boolean brace; 186 findElement(char buf[], int offset)187 private void findElement(char buf[], int offset) { 188 189 int list = offset; 190 int p; 191 int openBraces = 0; 192 boolean inQuotes = false; 193 int size = 0; 194 char c; 195 196 /* 197 * Skim off leading white space and check for 198 * an opening brace or 199 * quote. 200 */ 201 202 while (list < buf.length && Character.isSpace(buf[list])) { 203 list++; 204 } 205 206 if (list < buf.length && buf[list] == LBRACE) { 207 openBraces = 1; 208 list++; 209 } else if (list < buf.length && buf[list] == DQUOTE) { 210 inQuotes = true; 211 list++; 212 } 213 brace = (openBraces == 1); 214 p = list; 215 216 /* 217 * Find the end of the element (either a space or a 218 * close brace or 219 * the end of the string). 220 */ 221 222 try { 223 while (true) { 224 if (p < buf.length) 225 c = buf[p]; 226 else 227 c = 0; 228 switch (c) { 229 230 /* 231 * Open brace: don't treat specially unless 232 * the element is 233 * in braces. In this case, keep a nesting count. 234 */ 235 236 case LBRACE: 237 if (openBraces != 0) { 238 openBraces++; 239 } 240 break; 241 242 /* 243 * Close brace: if element is in braces, 244 * keep nesting 245 * count and quit when the last close brace 246 * is seen. 247 */ 248 249 case RBRACE: 250 if (openBraces == 1) { 251 int p2; 252 253 size = p - list; 254 p++; 255 if (p >= buf.length || buf[p] == 0 || 256 Character.isSpace(buf[p])) { 257 throw new DoneException(); 258 } 259 for (p2 = p; p2 < buf.length && buf[p2] != 0 && 260 !Character.isSpace(buf[p2]) && (p2 < p+20); 261 p2++) { 262 /* null body */ 263 } 264 265 String err = new String(buf, p, p2-p); 266 throw new ParseException( 267 /* JSTYLED */ 268 Global.fmtMsg("sunsoft.jws.visual.rt.type.ListParser.SpaceExpected", String.valueOf(buf, p, p2-p))); 269 270 } else if (openBraces != 0) { 271 openBraces--; 272 } 273 break; 274 275 /* 276 * Backslash: skip over everything up to 277 * the end of the 278 * backslash sequence. 279 */ 280 281 case BACKSLASH: { 282 IntHolder backslashSize = new IntHolder(); 283 backslash(buf, p, backslashSize); 284 p += backslashSize.value - 1; 285 break; 286 } 287 288 /* 289 * Space: ignore if element is in braces or 290 * quotes; otherwise 291 * terminate element. 292 */ 293 294 case SPACE: 295 case FORMFEED: 296 case NEWLINE: 297 case RETURN: 298 case TAB: 299 if ((openBraces == 0) && !inQuotes) { 300 size = p - list; 301 throw new DoneException(); 302 } 303 break; 304 305 /* 306 * Double-quote: if element is in quotes then 307 * terminate it. 308 */ 309 310 case DQUOTE: 311 if (inQuotes) { 312 int p2; 313 314 size = p-list; 315 p++; 316 if (p >= buf.length || buf[p] == 0 || 317 Character.isSpace(buf[p])) { 318 throw new DoneException(); 319 } 320 for (p2 = p; (p2 < buf.length && buf[p2] != 0) 321 && 322 (!Character.isSpace(buf[p2])) && (p2 < p+20); 323 p2++) { 324 /* null body */ 325 } 326 327 throw new ParseException( 328 /* JSTYLED */ 329 Global.fmtMsg("sunsoft.jws.visual.rt.type.ListParser.SpaceExpected2", 330 String.valueOf(buf, p, p2-p), String.valueOf 331 (buf, p, buf.length-1))); 332 333 } 334 break; 335 336 /* 337 * End of list: terminate element. 338 */ 339 340 case 0: 341 if (openBraces != 0) { 342 /* BEGIN JSTYLED */ 343 throw new ParseException(Global.getMsg("sunsoft.jws.visual.rt.type.ListParser.UnmatchedBrace")); 344 } else if (inQuotes) { 345 throw new ParseException(Global.getMsg("sunsoft.jws.visual.rt.type.ListParser.UnmatchedQuote")); 346 } 347 348 size = p - list; 349 throw new DoneException(); 350 } 351 p++; 352 } 353 } 354 catch (DoneException ex) { 355 } 356 357 while (p < buf.length && Character.isSpace(buf[p])) { 358 p++; 359 } 360 361 elementIndex = list; 362 nextIndex = p; 363 elementSize = size; 364 } 365 366 /* 367 *---------------------------------------------------------------------- 368 * 369 * collapse -- 370 * 371 * Return a new string after eliminating any backslashes that 372 * aren't in braces. 373 * 374 * Results: 375 * Returns a string that is a substring of buf starting at offset, 376 * and count characters long. If backslash sequences are found 377 * outside braces, the backslashes are eliminated in the new string. 378 * 379 * Side effects: 380 * None. 381 * 382 *---------------------------------------------------------------------- 383 */ 384 /* END JSTYLED */ 385 collapse(char buf[], int offset, int count)386 private String collapse(char buf[], int offset, int count) { 387 int p = offset; 388 char c; 389 IntHolder numRead = new IntHolder(); 390 char dst[] = new char[buf.length+1]; 391 int p2 = 0; 392 393 while (count > 0) { 394 if (p < buf.length) 395 c = buf[p]; 396 else 397 c = 0; 398 399 if (c == BACKSLASH) { 400 dst[p2] = backslash(buf, p, numRead); 401 p2++; 402 p += numRead.value-1; 403 count -= numRead.value-1; 404 } else { 405 dst[p2] = c; 406 p2++; 407 } 408 p++; 409 count--; 410 } 411 dst[p2] = 0; 412 413 return new String(dst, 0, p2); 414 } 415 416 /* 417 *------------------------------------------ 418 * 419 * backslash -- 420 * 421 * Figure out how to handle a backslash sequence. 422 * 423 * Results: 424 * The return value is the character that should be substituted 425 * in place of the backslash sequence that starts at src. 426 * The "readPtr" variable is set to the number of characters 427 * in the backslash sequence. 428 * 429 * Side effects: 430 * none 431 * 432 * Parameters: 433 * char buf[]; Character buffer containing 434 * the backslash 435 * sequence. 436 * int offset; Offset within buf where the backslash 437 * sequence begins. 438 *------------------------------------------ 439 */ 440 backslash(char buf[], int offset, IntHolder readPtr)441 private static char backslash(char buf[], int offset, 442 IntHolder readPtr) { 443 444 int p = offset+1; 445 char result; 446 int count; 447 char c; 448 449 count = 2; 450 451 if (p < buf.length) 452 c = buf[p]; 453 else 454 c = 0; 455 switch (c) { 456 case CHAR_a: 457 result = 0x7; /* Don't say '\a' here, */ 458 /* since some compilers */ 459 break; /* don't support it. */ 460 case CHAR_b: 461 result = BACKSPACE; 462 break; 463 case CHAR_f: 464 result = FORMFEED; 465 break; 466 case CHAR_n: 467 result = NEWLINE; 468 break; 469 case CHAR_r: 470 result = RETURN; 471 break; 472 case CHAR_t: 473 result = TAB; 474 break; 475 case CHAR_x: 476 if (isxdigit(buf[p+1])) { 477 int p2 = p+1; 478 while (isxdigit(buf[p2])) { 479 p2++; 480 } 481 482 result = (char) 483 Integer.parseInt(String.valueOf(buf, p+1, p2), 16); 484 count = p2 - offset; 485 } else { 486 count = 2; 487 result = CHAR_x; 488 } 489 break; 490 case NEWLINE: 491 do { 492 p++; 493 } while ((buf[p] == SPACE) || (buf[p] == TAB)); 494 result = SPACE; 495 count = p - offset; 496 break; 497 case 0: 498 result = BACKSLASH; 499 count = 1; 500 break; 501 default: 502 if (isdigit(buf[p])) { 503 result = (char)(buf[p] - ZERO); 504 p++; 505 if (!isdigit(buf[p])) { 506 break; 507 } 508 count = 3; 509 result = (char)((result << 3) + (buf[p] - ZERO)); 510 p++; 511 if (!isdigit(buf[p])) { 512 break; 513 } 514 count = 4; 515 result = (char)((result << 3) + (buf[p] - ZERO)); 516 break; 517 } 518 result = buf[p]; 519 count = 2; 520 break; 521 } 522 523 if (readPtr != null) 524 readPtr.value = count; 525 526 return result; 527 } 528 /* BEGIN JSTYLED */ 529 530 /* 531 * The following values are used in the flags 532 * returned by Tcl_ScanElement 533 * and used by Tcl_ConvertElement. The value 534 * TCL_DONT_USE_BRACES is also 535 * defined in tcl.h; make sure its value doesn't 536 * overlap with any of the 537 * values below. 538 * 539 * TCL_DONT_USE_BRACES - 1 means the string mustn't 540 * be enclosed in 541 * braces (e.g. it contains 542 * unmatched braces, 543 * or ends in a backslash 544 * character, or user 545 * just doesn't want braces); handle all 546 * special characters by adding 547 * backslashes. 548 * USE_BRACES - 1 means the string contains a special 549 * character that can be handled simply by 550 * enclosing the entire argument 551 * in braces. 552 * BRACES_UNMATCHED - 1 means that braces 553 * aren't properly matched 554 * in the argument. 555 */ 556 557 private static final int TCL_DONT_USE_BRACES = 1; 558 private static final int USE_BRACES = 2; 559 private static final int BRACES_UNMATCHED = 4; 560 561 /* 562 *----------------------------------- 563 * 564 * scanElement -- 565 * 566 * This procedure is a companion procedure to Tcl_ConvertElement. 567 * It scans a string to see what needs to be done to it (e.g. 568 * add backslashes or enclosing braces) to make the string into 569 * a valid Tcl list element. 570 * 571 * Results: 572 * The return value is an overestimate of the number of characters 573 * that will be needed by Tcl_ConvertElement to produce a valid 574 * list element from string. The word at *flagPtr is filled in 575 * with a value needed by Tcl_ConvertElement when doing the actual 576 * conversion. 577 * 578 * Side effects: 579 * None. 580 * 581 *--------------------------------------- 582 */ 583 584 // char *string; /* String to convert to Tcl list element. */ 585 // int *flagPtr; /* Where to store information to guide */ 586 // /* Tcl_ConvertElement. */ 587 588 scanElement(char buf[], IntHolder flagPtr)589 private static int scanElement(char buf[], IntHolder flagPtr) { 590 int flags, nestingLevel; 591 int p; 592 593 /* 594 * This procedure and Tcl_ConvertElement together 595 * do two things: 596 * 597 * 1. They produce a proper list, one that will yield back the 598 * argument strings when evaluated or when disassembled with 599 * Tcl_SplitList. This is the most important thing. 600 * 601 * 2. They try to produce legible output, which means 602 * minimizing the 603 * use of backslashes (using braces instead). However, 604 * there are 605 * some situations where backslashes must be used 606 * (e.g. an element 607 * like "{abc": the leading brace will have to be 608 * backslashed. For 609 * each element, one of three things must be done: 610 * 611 * (a) Use the element as-is (it doesn't contain 612 * anything special 613 * characters). This is the most desirable option. 614 * 615 * (b) Enclose the element in braces, but leave the 616 * contents alone. 617 * This happens if the element contains embedded space, 618 * or if it 619 * contains characters with special interpretation 620 * ($, [, ;, or \), 621 * or if it starts with a brace or double-quote, or 622 * if there are 623 * no characters in the element. 624 * 625 * (c) Don't enclose the element in braces, but 626 * add backslashes to 627 * prevent special interpretation of special characters. 628 * This is a 629 * last resort used when the argument would normally 630 * fall under case 631 * (b) but contains unmatched braces. It also occurs 632 * if the last 633 * character of the argument is a backslash or if the 634 * element contains 635 * a backslash followed by newline. 636 * 637 * The procedure figures out how many bytes will be 638 * needed to store 639 * the result (actually, it overestimates). It also 640 * collects information 641 * about the element in the form of a flags word. 642 */ 643 644 /* END JSTYLED */ 645 nestingLevel = 0; 646 flags = 0; 647 if (buf == null) { 648 buf = new char[0]; 649 } 650 p = 0; 651 if ((p >= buf.length) || (buf[p] == LBRACE) || 652 (buf[p] == DQUOTE) || (buf[p] == 0)) { 653 flags |= USE_BRACES; 654 } 655 for (; p < buf.length && buf[p] != 0; p++) { 656 switch (buf[p]) { 657 case LBRACE: 658 nestingLevel++; 659 break; 660 case RBRACE: 661 nestingLevel--; 662 if (nestingLevel < 0) { 663 flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; 664 } 665 break; 666 case SPACE: 667 case FORMFEED: 668 case NEWLINE: 669 case RETURN: 670 case TAB: 671 flags |= USE_BRACES; 672 break; 673 case BACKSLASH: 674 if ((buf[p+1] == 0) || (buf[p+1] == NEWLINE)) { 675 flags = TCL_DONT_USE_BRACES; 676 } else { 677 IntHolder size = new IntHolder(); 678 679 backslash(buf, p, size); 680 p += size.value-1; 681 flags |= USE_BRACES; 682 } 683 break; 684 } 685 } 686 if (nestingLevel != 0) { 687 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; 688 } 689 flagPtr.value = flags; 690 691 /* 692 * Allow enough space to backslash every character plus leave 693 * two spaces for braces. 694 */ 695 696 return 2*p + 2; 697 } 698 699 /* BEGIN JSTYLED */ 700 /* 701 *------------------------------------------ 702 * 703 * convertElement -- 704 * 705 * This is a companion procedure to scanElement. Given the 706 * information produced by scanElement, this procedure converts 707 * a string to a list element equal to that string. 708 * 709 * Results: 710 * Information is copied to *dst in the form of a list element 711 * identical to src (i.e. if Tcl_SplitList is applied to dst it 712 * will produce a string identical to src). The return value is 713 * a count of the number of characters copied (not including the 714 * terminating NULL character). 715 * 716 * Side effects: 717 * None. 718 * 719 *-------------------------------------- 720 */ 721 /* END JSTYLED */ 722 723 // register char *src; /* Source information for list element. */ 724 // char *dst; /* Place to put list-ified element. */ 725 // int flags; /* Flags produced by Tcl_ScanElement. */ 726 convertElement(char src[], char dst[], int flags)727 private static int convertElement(char src[], char dst[], 728 int flags) { 729 730 int p = 0; 731 732 /* 733 * See the comment block at the beginning 734 * of the Tcl_ScanElement 735 * code for details of how this works. 736 */ 737 738 if ((src == null) || (src.length == 0)) { 739 dst[p] = LBRACE; 740 dst[p+1] = RBRACE; 741 dst[p+2] = 0; 742 return 2; 743 } 744 if ((flags & USE_BRACES) != 0 && 745 (flags & TCL_DONT_USE_BRACES) == 0) { 746 dst[p] = LBRACE; 747 p++; 748 for (int p2 = 0; p2 < src.length && src[p2] != 0; 749 p++, p2++) { 750 dst[p] = src[p2]; 751 } 752 dst[p] = RBRACE; 753 p++; 754 } else { 755 int p2 = 0; 756 if (src[p2] == LBRACE) { 757 /* 758 * Can't have a leading brace unless 759 * the whole element is 760 * enclosed in braces. Add a backslash 761 * before the brace. 762 * Furthermore, this may destroy the 763 * balance between open 764 * and close braces, so set BRACES_UNMATCHED. 765 */ 766 767 dst[p] = BACKSLASH; 768 dst[p+1] = LBRACE; 769 p += 2; 770 p2++; 771 flags |= BRACES_UNMATCHED; 772 } 773 for (; p2 < src.length && src[p2] != 0; p2++) { 774 switch (src[p2]) { 775 case SPACE: 776 case BACKSLASH: 777 case DQUOTE: 778 dst[p] = BACKSLASH; 779 p++; 780 break; 781 case LBRACE: 782 case RBRACE: 783 /* BEGIN JSTYLED */ 784 /* 785 * It may not seem necessary to backslash 786 * braces, but 787 * it is. The reason for this is that 788 * the resulting 789 * list element may actually be an 790 * element of a sub-list 791 * enclosed in braces (e.g. if 792 * Tcl_DStringStartSublist 793 * has been invoked), so there may be a 794 * brace mismatch 795 * if the braces aren't backslashed. 796 */ 797 /* END JSTYLED */ 798 799 if ((flags & BRACES_UNMATCHED) != 0) { 800 dst[p] = BACKSLASH; 801 p++; 802 } 803 break; 804 case FORMFEED: 805 dst[p] = BACKSLASH; 806 p++; 807 dst[p] = CHAR_f; 808 p++; 809 continue; 810 case NEWLINE: 811 dst[p] = BACKSLASH; 812 p++; 813 dst[p] = CHAR_n; 814 p++; 815 continue; 816 case RETURN: 817 dst[p] = BACKSLASH; 818 p++; 819 dst[p] = CHAR_r; 820 p++; 821 continue; 822 case TAB: 823 dst[p] = BACKSLASH; 824 p++; 825 dst[p] = CHAR_t; 826 p++; 827 continue; 828 } 829 dst[p] = src[p2]; 830 p++; 831 } 832 } 833 dst[p] = NULL; 834 return p; 835 } 836 837 /* 838 * Returns a new string that is a listified version of the string 839 * argument. The string will be enclosed with braces if necessary, 840 * and all special characters will be escaped. 841 */ list(String string)842 public static String list(String string) { 843 char src[] = string.toCharArray(); 844 845 IntHolder flagPtr = new IntHolder(); 846 int len = scanElement(src, flagPtr); 847 char dst[] = new char[len+1]; 848 len = convertElement(src, dst, flagPtr.value); 849 850 return new String(dst, 0, len); 851 } 852 853 /* 854 * Appends a new string to the string buffer argument that is a 855 * listified version of the string argument. The string will be 856 * enclosed with braces if necessary, and all special characters 857 * will be escaped. 858 */ list(String string, StringBuffer buf)859 public static void list(String string, StringBuffer buf) { 860 char src[] = string.toCharArray(); 861 862 IntHolder flagPtr = new IntHolder(); 863 int len = scanElement(src, flagPtr); 864 char dst[] = new char[len+1]; 865 len = convertElement(src, dst, flagPtr.value); 866 867 buf.append(dst, 0, len); 868 } 869 870 /* 871 * Returns a new string that is a quoted version of the string 872 * argument. The string will be enclosed with quotes if necessary, 873 * and all special characters will be escaped. If the forceQuotes 874 * argument is true, then the string will be enclosed with quotes 875 * even if it is not strictly necessary. Also, if forceQuotes 876 * is true, then the '\n' character will be replaced with the 877 * string "\n". 878 */ quote(String string, boolean forceQuotes)879 public static String quote(String string, boolean forceQuotes) { 880 char src[] = string.toCharArray(); 881 char dst[] = quote(src, forceQuotes); 882 return new String(dst); 883 } 884 885 /* 886 * Appends a new string to the string buffer argument that is a 887 * quoted version of the string argument. The string will be 888 * enclosed with quotes if necessary, and all special characters 889 * will be escaped. If the forceQuotes argument is true, then the 890 * string will be enclosed with quotes even if it is not strictly 891 * necessary. Also, if forceQuotes is true, then the '\n' 892 * character 893 * will be replaced with the string "\n". 894 */ quote(String string, StringBuffer buf, boolean forceQuotes)895 public static void quote(String string, StringBuffer buf, 896 boolean forceQuotes) { 897 char src[] = string.toCharArray(); 898 char dst[] = quote(src, forceQuotes); 899 buf.append(dst); 900 } 901 /* BEGIN JSTYLED */ 902 /** 903 * Puts quotes around the given character array if it 904 * contains spaces 905 * or double-quotes. Only part of the string buffer 906 * is quoted, determined 907 * by the "startIndex" argument. The substring of the 908 * buffer starting 909 * at "startIndex" and ending at the end of the buffer is quoted. 910 * This method operates on a string buffer instead of a string for 911 * improved performance. 912 * 913 * The "quote" method also does escaping. A backslash is placed in 914 * front of any double-quote or backslash in the string 915 * itself. Also, 916 * new-line characters are replaced with the 917 * characters \ and n 918 * 919 * Added argument: forceQuotes. If this is true, then 920 * always put quotes 921 * around the text (necessary for code generation). 922 * Also, replace the 923 * '\n' character with the string "\n". 924 */ 925 /* END JSTYLED */ quote(char src[], boolean forceQuotes)926 public static char[] quote(char src[], boolean forceQuotes) { 927 boolean needQuotes; 928 int backslash = 0; 929 930 if (src.length == 0) { 931 needQuotes = true; 932 } else { 933 needQuotes = false; 934 if (!forceQuotes && src[0] == LBRACE && 935 src[src.length-1] == RBRACE) { 936 return src; 937 } 938 } 939 940 for (int i = 0; i < src.length; i++) { 941 switch (src[i]) { 942 case LBRACE: 943 case RBRACE: 944 case SPACE: 945 case TAB: 946 needQuotes = true; 947 break; 948 949 case DQUOTE: 950 case BACKSLASH: 951 needQuotes = true; 952 backslash++; 953 break; 954 955 case FORMFEED: 956 case RETURN: 957 case NEWLINE: 958 needQuotes = true; 959 if (forceQuotes) 960 backslash++; 961 break; 962 } 963 } 964 965 int len = src.length + backslash; 966 if (needQuotes || forceQuotes) 967 len += 2; 968 969 char dst[] = new char[len]; 970 int p = 0; 971 972 if (needQuotes || forceQuotes) 973 dst[p++] = DQUOTE; 974 975 for (int i = 0; i < src.length; i++) { 976 switch (src[i]) { 977 case DQUOTE: 978 case BACKSLASH: 979 dst[p++] = BACKSLASH; 980 break; 981 982 case FORMFEED: 983 case RETURN: 984 case NEWLINE: 985 if (forceQuotes) { 986 dst[p++] = BACKSLASH; 987 switch (src[i]) { 988 case FORMFEED: 989 dst[p++] = CHAR_f; 990 break; 991 case RETURN: 992 dst[p++] = CHAR_r; 993 break; 994 case NEWLINE: 995 dst[p++] = CHAR_n; 996 break; 997 } 998 continue; 999 } 1000 break; 1001 } 1002 dst[p++] = src[i]; 1003 } 1004 1005 if (needQuotes || forceQuotes) 1006 dst[p++] = DQUOTE; 1007 1008 return dst; 1009 } 1010 /* BEGIN JSTYLED */ 1011 /** 1012 * Returns a string that can be used as a newline. 1013 * This string includes 1014 * a carriage return if we are running on Windows. 1015 */ 1016 /* END JSTYLED */ newline()1017 public static String newline() { 1018 return (Global.newline()); 1019 } 1020 1021 /** 1022 * Appends a newline to buf. This also appends a carriage return 1023 * if we are running on Windows. 1024 */ newline(StringBuffer buf)1025 public static void newline(StringBuffer buf) { 1026 Global.newline(buf); 1027 } 1028 1029 private static final String indentString = /* NOI18N */" "; 1030 1031 /** 1032 * Indents "buf" based on the given indent level. 1033 */ indent(StringBuffer buf, int indentLevel)1034 public static void indent(StringBuffer buf, int indentLevel) { 1035 for (int i = 0; i < indentLevel; i++) 1036 buf.append(indentString); 1037 } 1038 isdigit(char ch)1039 public static boolean isdigit(char ch) { 1040 return Character.isDigit(ch); 1041 } 1042 isxdigit(char ch)1043 public static boolean isxdigit(char ch) { 1044 return 1045 ((ch >= ZERO) && (ch <= NINE)) || 1046 ((ch >= CHAR_A) && (ch <= CHAR_F)) || 1047 ((ch >= CHAR_a) && (ch <= CHAR_f)); 1048 } 1049 getListElements(String s, int mult)1050 public static Enumeration getListElements(String s, int mult) { 1051 ListParser parser = new ListParser(s); 1052 1053 // if ((parser.size() % mult) != 0) { 1054 /* JSTYLED */ 1055 // System.out.println("ParseWarning: Expecting a multiple of " + mult + 1056 // " list elements, got " + parser.size()); 1057 // } 1058 1059 return parser.elements(); 1060 } 1061 makeListTable(String s)1062 public static Hashtable makeListTable(String s) { 1063 Enumeration e = getListElements(s, 2); 1064 Hashtable table = new Hashtable(); 1065 while (e.hasMoreElements()) { 1066 try { 1067 table.put((String)e.nextElement(), 1068 (String)e.nextElement()); 1069 } 1070 catch (NoSuchElementException ex) { 1071 /* JSTYLED */ 1072 throw new ParseException(Global.fmtMsg("sunsoft.jws.visual.rt.type.ListParser.ExpectingTwoElements", s)); 1073 } 1074 } 1075 return table; 1076 } 1077 parseInt(String s)1078 public static int parseInt(String s) { 1079 try { 1080 return Integer.parseInt(s); 1081 } 1082 catch (NumberFormatException ex) { 1083 throw new ParseException(/* NOI18N */"\n\t" + 1084 ex.toString()); 1085 } 1086 } 1087 } 1088 1089 1090 /** 1091 * An Exception that can be thrown and caught internally by ListParser. 1092 * 1093 * @see ListParser 1094 * @version 1.16, 07/25/97 1095 */ 1096 class DoneException extends Exception { DoneException()1097 DoneException() { 1098 super(); 1099 } 1100 DoneException(String message)1101 DoneException(String message) { 1102 super(message); 1103 } 1104 } 1105