001 /*
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
005 *
006 * The contents of this file are subject to the terms of either the GNU
007 * General Public License Version 2 only ("GPL") or the Common Development
008 * and Distribution License("CDDL") (collectively, the "License"). You
009 * may not use this file except in compliance with the License. You can
010 * obtain a copy of the License at
011 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
012 * or packager/legal/LICENSE.txt. See the License for the specific
013 * language governing permissions and limitations under the License.
014 *
015 * When distributing the software, include this License Header Notice in each
016 * file and include the License file at packager/legal/LICENSE.txt.
017 *
018 * GPL Classpath Exception:
019 * Oracle designates this particular file as subject to the "Classpath"
020 * exception as provided by Oracle in the GPL Version 2 section of the License
021 * file that accompanied this code.
022 *
023 * Modifications:
024 * If applicable, add the following below the License Header, with the fields
025 * enclosed by brackets [] replaced by your own identifying information:
026 * "Portions Copyright [year] [name of copyright owner]"
027 *
028 * Contributor(s):
029 * If you wish your version of this file to be governed by only the CDDL or
030 * only the GPL Version 2, indicate your decision by adding "[Contributor]
031 * elects to include this software in this distribution under the [CDDL or GPL
032 * Version 2] license." If you don't indicate a single choice of license, a
033 * recipient has the option to distribute your version of this file under
034 * either the CDDL, the GPL Version 2 or to extend the choice of license to
035 * its licensees as provided above. However, if you add GPL Version 2 code
036 * and therefore, elected the GPL Version 2 license, then the option applies
037 * only if the new code is made subject to such option by the copyright
038 * holder.
039 */
040
041 package com.sun.enterprise.admin.cli;
042
043 import java.io.*;
044 import java.util.*;
045 import com.sun.enterprise.universal.i18n.LocalStringsImpl;
046
047 public class ArgumentTokenizer {
048 protected int currentPosition;
049 protected int maxPosition;
050 protected String str;
051 protected StringBuilder token = new StringBuilder();
052
053 private static final LocalStringsImpl strings =
054 new LocalStringsImpl(ArgumentTokenizer.class);
055
056 public static class ArgumentException extends Exception {
057 public ArgumentException(String s) {
058 super(s);
059 }
060 }
061
062 /**
063 * Construct a tokenizer for the specified string.
064 *
065 * @param str a string to be parsed.
066 */
067 public ArgumentTokenizer(String str) {
068 currentPosition = 0;
069 this.str = str;
070 maxPosition = str.length();
071 }
072
073 /**
074 * Skip white space.
075 */
076 protected void skipWhiteSpace() {
077 while ((currentPosition < maxPosition) &&
078 Character.isWhitespace(str.charAt(currentPosition))) {
079 currentPosition++;
080 }
081 }
082
083 /**
084 * Test if there are more tokens available from this tokenizer's string.
085 *
086 * @return <code>true</code> if there are more tokens available from this
087 * tokenizer's string; <code>false</code> otherwise.
088 */
089 public boolean hasMoreTokens() {
090 skipWhiteSpace();
091 return (currentPosition < maxPosition);
092 }
093
094 /**
095 * Return the next token from this tokenizer.
096 *
097 * @return the next token from this tokenizer.
098 * @exception NoSuchElementException if there are no more tokens in this
099 * tokenizer's string.
100 */
101 public String nextToken() throws ArgumentTokenizer.ArgumentException {
102 skipWhiteSpace();
103 if (currentPosition >= maxPosition) {
104 throw new NoSuchElementException(strings.get("token.noMoreTokens"));
105 }
106 return scanToken();
107 }
108
109 /**
110 * Return the next token starting at the current position,
111 * assuming whitespace has already been skipped.
112 */
113 protected String scanToken() throws ArgumentTokenizer.ArgumentException {
114 while (currentPosition < maxPosition) {
115 char c = str.charAt(currentPosition++);
116 if (c == '"' || c == '\'') {
117 char quote = c;
118 while (currentPosition < maxPosition) {
119 c = str.charAt(currentPosition++);
120 if (c == '\\' && quote == '"') {
121 if (currentPosition >= maxPosition)
122 throw new ArgumentTokenizer.ArgumentException(
123 strings.get("token.escapeAtEOL"));
124 c = str.charAt(currentPosition++);
125 if (!(c == '\\' || c == '"' || c == '\''))
126 token.append('\\');
127 } else if (c == quote) {
128 break;
129 }
130 token.append(c);
131 }
132 if (c != quote)
133 throw new ArgumentTokenizer.ArgumentException(
134 strings.get("token.unbalancedQuotes"));
135 } else if (c == '\\') {
136 if (currentPosition >= maxPosition)
137 throw new ArgumentTokenizer.ArgumentException(
138 strings.get("token.escapeAtEOL"));
139 c = str.charAt(currentPosition++);
140 token.append(c);
141 } else if (Character.isWhitespace(c)) {
142 break;
143 } else {
144 token.append(c);
145 }
146 }
147 String s = token.toString();
148 token.setLength(0);
149 return s;
150 }
151 }