001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.util;
019:
020: import java.io.PrintWriter;
021: import java.io.StringWriter;
022: import java.util.Vector;
023:
024: /**
025: * A set of helper methods related to string manipulation.
026: *
027: */
028: public final class StringUtils {
029:
030: /**
031: * constructor to stop anyone instantiating the class
032: */
033: private StringUtils() {
034: }
035:
036: /** the line separator for this OS */
037: public static final String LINE_SEP = System
038: .getProperty("line.separator");
039:
040: /**
041: * Splits up a string into a list of lines. It is equivalent
042: * to <tt>split(data, '\n')</tt>.
043: * @param data the string to split up into lines.
044: * @return the list of lines available in the string.
045: */
046: public static Vector lineSplit(String data) {
047: return split(data, '\n');
048: }
049:
050: /**
051: * Splits up a string where elements are separated by a specific
052: * character and return all elements.
053: * @param data the string to split up.
054: * @param ch the separator character.
055: * @return the list of elements.
056: */
057: public static Vector split(String data, int ch) {
058: Vector elems = new Vector();
059: int pos = -1;
060: int i = 0;
061: while ((pos = data.indexOf(ch, i)) != -1) {
062: String elem = data.substring(i, pos);
063: elems.addElement(elem);
064: i = pos + 1;
065: }
066: elems.addElement(data.substring(i));
067: return elems;
068: }
069:
070: /**
071: * Replace occurrences into a string.
072: * @param data the string to replace occurrences into
073: * @param from the occurrence to replace.
074: * @param to the occurrence to be used as a replacement.
075: * @return the new string with replaced occurrences.
076: */
077: public static String replace(String data, String from, String to) {
078: StringBuffer buf = new StringBuffer(data.length());
079: int pos = -1;
080: int i = 0;
081: while ((pos = data.indexOf(from, i)) != -1) {
082: buf.append(data.substring(i, pos)).append(to);
083: i = pos + from.length();
084: }
085: buf.append(data.substring(i));
086: return buf.toString();
087: }
088:
089: /**
090: * Convenient method to retrieve the full stacktrace from a given exception.
091: * @param t the exception to get the stacktrace from.
092: * @return the stacktrace from the given exception.
093: */
094: public static String getStackTrace(Throwable t) {
095: StringWriter sw = new StringWriter();
096: PrintWriter pw = new PrintWriter(sw, true);
097: t.printStackTrace(pw);
098: pw.flush();
099: pw.close();
100: return sw.toString();
101: }
102:
103: /**
104: * Checks that a string buffer ends up with a given string. It may sound
105: * trivial with the existing
106: * JDK API but the various implementation among JDKs can make those
107: * methods extremely resource intensive
108: * and perform poorly due to massive memory allocation and copying. See
109: * @param buffer the buffer to perform the check on
110: * @param suffix the suffix
111: * @return <code>true</code> if the character sequence represented by the
112: * argument is a suffix of the character sequence represented by
113: * the StringBuffer object; <code>false</code> otherwise. Note that the
114: * result will be <code>true</code> if the argument is the
115: * empty string.
116: */
117: public static boolean endsWith(StringBuffer buffer, String suffix) {
118: if (suffix.length() > buffer.length()) {
119: return false;
120: }
121: // this loop is done on purpose to avoid memory allocation performance
122: // problems on various JDKs
123: // StringBuffer.lastIndexOf() was introduced in jdk 1.4 and
124: // implementation is ok though does allocation/copying
125: // StringBuffer.toString().endsWith() does massive memory
126: // allocation/copying on JDK 1.5
127: // See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169
128: int endIndex = suffix.length() - 1;
129: int bufferIndex = buffer.length() - 1;
130: while (endIndex >= 0) {
131: if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) {
132: return false;
133: }
134: bufferIndex--;
135: endIndex--;
136: }
137: return true;
138: }
139:
140: /**
141: * xml does not do "c" like interpretation of strings.
142: * i.e. \n\r\t etc.
143: * this method processes \n, \r, \t, \f, \\
144: * also subs \s -> " \n\r\t\f"
145: * a trailing '\' will be ignored
146: *
147: * @param input raw string with possible embedded '\'s
148: * @return converted string
149: * @since Ant 1.7
150: */
151: public static String resolveBackSlash(String input) {
152: StringBuffer b = new StringBuffer();
153: boolean backSlashSeen = false;
154: for (int i = 0; i < input.length(); ++i) {
155: char c = input.charAt(i);
156: if (!backSlashSeen) {
157: if (c == '\\') {
158: backSlashSeen = true;
159: } else {
160: b.append(c);
161: }
162: } else {
163: switch (c) {
164: case '\\':
165: b.append((char) '\\');
166: break;
167: case 'n':
168: b.append((char) '\n');
169: break;
170: case 'r':
171: b.append((char) '\r');
172: break;
173: case 't':
174: b.append((char) '\t');
175: break;
176: case 'f':
177: b.append((char) '\f');
178: break;
179: case 's':
180: b.append(" \t\n\r\f");
181: break;
182: default:
183: b.append(c);
184: }
185: backSlashSeen = false;
186: }
187: }
188: return b.toString();
189: }
190:
191: /**
192: * Takes a human readable size representation eg 10K
193: * a long value. Doesn't support 1.1K or other rational values.
194: * @param humanSize
195: * @return a long value representation
196: * @throws Exception
197: * @since Ant 1.7
198: */
199: public static long parseHumanSizes(String humanSize)
200: throws Exception {
201: final long KILOBYTE = 1024;
202: final long MEGABYTE = KILOBYTE * 1024;
203: final long GIGABYTE = MEGABYTE * 1024;
204: final long TERABYTE = GIGABYTE * 1024;
205: final long PETABYTE = TERABYTE * 1024;
206: //last character isn't a digit
207: if (!Character
208: .isDigit(humanSize.charAt(humanSize.length() - 1))) {
209: char c = humanSize.charAt(humanSize.length() - 1);
210: long value = Long.valueOf(
211: humanSize.substring(0, humanSize.length() - 1))
212: .longValue();
213: switch (c) {
214: case 'K':
215: return value * KILOBYTE;
216: case 'M':
217: return value * MEGABYTE;
218: case 'G':
219: return value * GIGABYTE;
220: case 'T':
221: return value * TERABYTE;
222: case 'P':
223: return value * PETABYTE;
224: default:
225: return value;
226: }
227: } else {
228: return Long.parseLong(humanSize);
229: }
230: }
231: }
|