xref: /titanic_41/usr/src/cmd/krb5/kadmin/gui/visualrt/sunsoft/jws/visual/rt/type/ListParser.java (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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