ListParser.java revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
/*
* Copyright (C) 1996 Active Software, Inc.
* All rights reserved.
*
* @(#) ListParser.java 1.16 - last change made 07/25/97
*/
/**
* Utility class for parsing lists of things in the style of Tcl.
*
* @version 1.16, 07/25/97
*/
public class ListParser {
// Character constants
int begin = 0;
}
else
}
if (begin < 0)
begin = 0;
}
public Enumeration elements() {
}
public int size() {
}
}
nextIndex = 0;
try {
}
catch (ParseException ex) {
throw ex;
}
if (elementSize != 0 ||
if (brace) {
elementSize));
} else {
elementSize));
}
}
}
}
/* BEGIN JSTYLED */
/*
*----------------------------------------------------------------------
*
* findElement --
*
* Given a character buffer containing a Tcl list, locate the first
* (or next) element in the list.
*
* Results:
* None.
*
* Side effects:
* If an exception is not thrown, then elementIndex will be set to
* the position of the first element of the list,
* and nextIndex will
* be set to the position of the character just after
* any white space
* following the last character that's part of the element. If this
* is the last argument in the list, then nextIndex will point to the
* NULL character at the end of list. elementSize is set to
* the number of characters in the element. If the element is in
* braces, then elementIndex will point to the character after the
* opening brace and elementSize will not include either of the braces.
* If there isn't an element in the list, elementSize will be zero,
* elementIndex will refer to the null character at the end of list,
* and brace will be set to true.
*
* Note: this procedure does NOT collapse backslash sequences.
*
*----------------------------------------------------------------------
*/
/* END JSTYLED */
// Side effect variables
private int elementIndex;
private int nextIndex;
private int elementSize;
private boolean brace;
int p;
int openBraces = 0;
boolean inQuotes = false;
int size = 0;
char c;
/*
* Skim off leading white space and check for
* an opening brace or
* quote.
*/
list++;
}
openBraces = 1;
list++;
inQuotes = true;
list++;
}
p = list;
/*
* Find the end of the element (either a space or a
* close brace or
* the end of the string).
*/
try {
while (true) {
c = buf[p];
else
c = 0;
switch (c) {
/*
* Open brace: don't treat specially unless
* the element is
* in braces. In this case, keep a nesting count.
*/
case LBRACE:
if (openBraces != 0) {
openBraces++;
}
break;
/*
* Close brace: if element is in braces,
* keep nesting
* count and quit when the last close brace
* is seen.
*/
case RBRACE:
if (openBraces == 1) {
int p2;
p++;
throw new DoneException();
}
p2++) {
/* null body */
}
throw new ParseException(
/* JSTYLED */
Global.fmtMsg("sunsoft.jws.visual.rt.type.ListParser.SpaceExpected", String.valueOf(buf, p, p2-p)));
} else if (openBraces != 0) {
openBraces--;
}
break;
/*
* Backslash: skip over everything up to
* the end of the
* backslash sequence.
*/
case BACKSLASH: {
break;
}
/*
* Space: ignore if element is in braces or
* quotes; otherwise
* terminate element.
*/
case SPACE:
case FORMFEED:
case NEWLINE:
case RETURN:
case TAB:
throw new DoneException();
}
break;
/*
* Double-quote: if element is in quotes then
* terminate it.
*/
case DQUOTE:
if (inQuotes) {
int p2;
p++;
throw new DoneException();
}
&&
p2++) {
/* null body */
}
throw new ParseException(
/* JSTYLED */
}
break;
/*
* End of list: terminate element.
*/
case 0:
if (openBraces != 0) {
/* BEGIN JSTYLED */
} else if (inQuotes) {
}
throw new DoneException();
}
p++;
}
}
catch (DoneException ex) {
}
p++;
}
elementIndex = list;
nextIndex = p;
elementSize = size;
}
/*
*----------------------------------------------------------------------
*
* collapse --
*
* Return a new string after eliminating any backslashes that
* aren't in braces.
*
* Results:
* Returns a string that is a substring of buf starting at offset,
* and count characters long. If backslash sequences are found
* outside braces, the backslashes are eliminated in the new string.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* END JSTYLED */
int p = offset;
char c;
int p2 = 0;
while (count > 0) {
c = buf[p];
else
c = 0;
if (c == BACKSLASH) {
p2++;
} else {
p2++;
}
p++;
count--;
}
}
/*
*------------------------------------------
*
* backslash --
*
* Figure out how to handle a backslash sequence.
*
* Results:
* The return value is the character that should be substituted
* in place of the backslash sequence that starts at src.
* The "readPtr" variable is set to the number of characters
* in the backslash sequence.
*
* Side effects:
* none
*
* Parameters:
* char buf[]; Character buffer containing
* the backslash
* sequence.
* int offset; Offset within buf where the backslash
* sequence begins.
*------------------------------------------
*/
int p = offset+1;
char result;
int count;
char c;
count = 2;
c = buf[p];
else
c = 0;
switch (c) {
case CHAR_a:
/* since some compilers */
break; /* don't support it. */
case CHAR_b:
break;
case CHAR_f:
break;
case CHAR_n:
break;
case CHAR_r:
break;
case CHAR_t:
break;
case CHAR_x:
int p2 = p+1;
p2++;
}
result = (char)
} else {
count = 2;
}
break;
case NEWLINE:
do {
p++;
break;
case 0:
count = 1;
break;
default:
p++;
break;
}
count = 3;
p++;
break;
}
count = 4;
break;
}
count = 2;
break;
}
return result;
}
/* BEGIN JSTYLED */
/*
* The following values are used in the flags
* returned by Tcl_ScanElement
* and used by Tcl_ConvertElement. The value
* TCL_DONT_USE_BRACES is also
* defined in tcl.h; make sure its value doesn't
* overlap with any of the
* values below.
*
* TCL_DONT_USE_BRACES - 1 means the string mustn't
* be enclosed in
* braces (e.g. it contains
* unmatched braces,
* or ends in a backslash
* character, or user
* just doesn't want braces); handle all
* special characters by adding
* backslashes.
* USE_BRACES - 1 means the string contains a special
* character that can be handled simply by
* enclosing the entire argument
* in braces.
* BRACES_UNMATCHED - 1 means that braces
* aren't properly matched
* in the argument.
*/
private static final int TCL_DONT_USE_BRACES = 1;
private static final int USE_BRACES = 2;
private static final int BRACES_UNMATCHED = 4;
/*
*-----------------------------------
*
* scanElement --
*
* This procedure is a companion procedure to Tcl_ConvertElement.
* It scans a string to see what needs to be done to it (e.g.
* add backslashes or enclosing braces) to make the string into
* a valid Tcl list element.
*
* Results:
* The return value is an overestimate of the number of characters
* that will be needed by Tcl_ConvertElement to produce a valid
* list element from string. The word at *flagPtr is filled in
* with a value needed by Tcl_ConvertElement when doing the actual
* conversion.
*
* Side effects:
* None.
*
*---------------------------------------
*/
// char *string; /* String to convert to Tcl list element. */
// int *flagPtr; /* Where to store information to guide */
// /* Tcl_ConvertElement. */
int flags, nestingLevel;
int p;
/*
* This procedure and Tcl_ConvertElement together
* do two things:
*
* 1. They produce a proper list, one that will yield back the
* argument strings when evaluated or when disassembled with
* Tcl_SplitList. This is the most important thing.
*
* 2. They try to produce legible output, which means
* minimizing the
* use of backslashes (using braces instead). However,
* there are
* some situations where backslashes must be used
* (e.g. an element
* like "{abc": the leading brace will have to be
* backslashed. For
* each element, one of three things must be done:
*
* (a) Use the element as-is (it doesn't contain
* anything special
* characters). This is the most desirable option.
*
* (b) Enclose the element in braces, but leave the
* contents alone.
* This happens if the element contains embedded space,
* or if it
* contains characters with special interpretation
* ($, [, ;, or \),
* or if it starts with a brace or double-quote, or
* if there are
* no characters in the element.
*
* (c) Don't enclose the element in braces, but
* add backslashes to
* prevent special interpretation of special characters.
* This is a
* last resort used when the argument would normally
* fall under case
* (b) but contains unmatched braces. It also occurs
* if the last
* character of the argument is a backslash or if the
* element contains
* a backslash followed by newline.
*
* The procedure figures out how many bytes will be
* needed to store
* the result (actually, it overestimates). It also
* collects information
* about the element in the form of a flags word.
*/
/* END JSTYLED */
nestingLevel = 0;
flags = 0;
buf = new char[0];
}
p = 0;
flags |= USE_BRACES;
}
switch (buf[p]) {
case LBRACE:
nestingLevel++;
break;
case RBRACE:
nestingLevel--;
if (nestingLevel < 0) {
}
break;
case SPACE:
case FORMFEED:
case NEWLINE:
case RETURN:
case TAB:
flags |= USE_BRACES;
break;
case BACKSLASH:
} else {
flags |= USE_BRACES;
}
break;
}
}
if (nestingLevel != 0) {
}
/*
* Allow enough space to backslash every character plus leave
* two spaces for braces.
*/
return 2*p + 2;
}
/* BEGIN JSTYLED */
/*
*------------------------------------------
*
* convertElement --
*
* This is a companion procedure to scanElement. Given the
* information produced by scanElement, this procedure converts
* a string to a list element equal to that string.
*
* Results:
* Information is copied to *dst in the form of a list element
* identical to src (i.e. if Tcl_SplitList is applied to dst it
* will produce a string identical to src). The return value is
* a count of the number of characters copied (not including the
* terminating NULL character).
*
* Side effects:
* None.
*
*--------------------------------------
*/
/* END JSTYLED */
// register char *src; /* Source information for list element. */
// char *dst; /* Place to put list-ified element. */
// int flags; /* Flags produced by Tcl_ScanElement. */
int flags) {
int p = 0;
/*
* See the comment block at the beginning
* of the Tcl_ScanElement
* code for details of how this works.
*/
return 2;
}
p++;
p++, p2++) {
}
p++;
} else {
int p2 = 0;
/*
* Can't have a leading brace unless
* the whole element is
* enclosed in braces. Add a backslash
* before the brace.
* Furthermore, this may destroy the
* balance between open
* and close braces, so set BRACES_UNMATCHED.
*/
p += 2;
p2++;
}
case SPACE:
case BACKSLASH:
case DQUOTE:
p++;
break;
case LBRACE:
case RBRACE:
/* BEGIN JSTYLED */
/*
* It may not seem necessary to backslash
* braces, but
* it is. The reason for this is that
* the resulting
* list element may actually be an
* element of a sub-list
* enclosed in braces (e.g. if
* Tcl_DStringStartSublist
* has been invoked), so there may be a
* brace mismatch
* if the braces aren't backslashed.
*/
/* END JSTYLED */
p++;
}
break;
case FORMFEED:
p++;
p++;
continue;
case NEWLINE:
p++;
p++;
continue;
case RETURN:
p++;
p++;
continue;
case TAB:
p++;
p++;
continue;
}
p++;
}
}
return p;
}
/*
* Returns a new string that is a listified version of the string
* argument. The string will be enclosed with braces if necessary,
* and all special characters will be escaped.
*/
}
/*
* Appends a new string to the string buffer argument that is a
* listified version of the string argument. The string will be
* enclosed with braces if necessary, and all special characters
* will be escaped.
*/
}
/*
* Returns a new string that is a quoted version of the string
* argument. The string will be enclosed with quotes if necessary,
* and all special characters will be escaped. If the forceQuotes
* argument is true, then the string will be enclosed with quotes
* even if it is not strictly necessary. Also, if forceQuotes
* is true, then the '\n' character will be replaced with the
* string "\n".
*/
}
/*
* Appends a new string to the string buffer argument that is a
* quoted version of the string argument. The string will be
* enclosed with quotes if necessary, and all special characters
* will be escaped. If the forceQuotes argument is true, then the
* string will be enclosed with quotes even if it is not strictly
* necessary. Also, if forceQuotes is true, then the '\n'
* character
* will be replaced with the string "\n".
*/
boolean forceQuotes) {
}
/* BEGIN JSTYLED */
/**
* Puts quotes around the given character array if it
* contains spaces
* or double-quotes. Only part of the string buffer
* is quoted, determined
* by the "startIndex" argument. The substring of the
* buffer starting
* at "startIndex" and ending at the end of the buffer is quoted.
* This method operates on a string buffer instead of a string for
* improved performance.
*
* The "quote" method also does escaping. A backslash is placed in
* front of any double-quote or backslash in the string
* itself. Also,
* new-line characters are replaced with the
* characters \ and n
*
* Added argument: forceQuotes. If this is true, then
* always put quotes
* around the text (necessary for code generation).
* Also, replace the
* '\n' character with the string "\n".
*/
/* END JSTYLED */
boolean needQuotes;
int backslash = 0;
needQuotes = true;
} else {
needQuotes = false;
return src;
}
}
switch (src[i]) {
case LBRACE:
case RBRACE:
case SPACE:
case TAB:
needQuotes = true;
break;
case DQUOTE:
case BACKSLASH:
needQuotes = true;
backslash++;
break;
case FORMFEED:
case RETURN:
case NEWLINE:
needQuotes = true;
if (forceQuotes)
backslash++;
break;
}
}
if (needQuotes || forceQuotes)
len += 2;
int p = 0;
if (needQuotes || forceQuotes)
switch (src[i]) {
case DQUOTE:
case BACKSLASH:
break;
case FORMFEED:
case RETURN:
case NEWLINE:
if (forceQuotes) {
switch (src[i]) {
case FORMFEED:
break;
case RETURN:
break;
case NEWLINE:
break;
}
continue;
}
break;
}
}
if (needQuotes || forceQuotes)
return dst;
}
/* BEGIN JSTYLED */
/**
* Returns a string that can be used as a newline.
* This string includes
* a carriage return if we are running on Windows.
*/
/* END JSTYLED */
}
/**
* Appends a newline to buf. This also appends a carriage return
* if we are running on Windows.
*/
}
/**
* Indents "buf" based on the given indent level.
*/
for (int i = 0; i < indentLevel; i++)
}
}
return
}
// if ((parser.size() % mult) != 0) {
/* JSTYLED */
// System.out.println("ParseWarning: Expecting a multiple of " + mult +
// " list elements, got " + parser.size());
// }
}
while (e.hasMoreElements()) {
try {
(String)e.nextElement());
}
catch (NoSuchElementException ex) {
/* JSTYLED */
throw new ParseException(Global.fmtMsg("sunsoft.jws.visual.rt.type.ListParser.ExpectingTwoElements", s));
}
}
return table;
}
try {
}
catch (NumberFormatException ex) {
}
}
}
/**
* An Exception that can be thrown and caught internally by ListParser.
*
* @see ListParser
* @version 1.16, 07/25/97
*/
class DoneException extends Exception {
DoneException() {
super();
}
super(message);
}
}