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 019 package org.apache.commons.exec.util; 020 021 022 import java.util.ArrayList; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.StringTokenizer; 026 import java.io.File; 027 028 /** 029 * Supplement of commons-lang, the stringSubstitution() was in a simpler 030 * implementation available in an older commons-lang implementation. 031 * 032 * Furthermore a place to put reusable and/or ugly code. 033 * 034 * This class is not part of the public API and could change without 035 * warning. 036 * 037 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 038 */ 039 public class StringUtils { 040 041 private static final String SINGLE_QUOTE = "\'"; 042 private static final String DOUBLE_QUOTE = "\""; 043 private static final char SLASH_CHAR = '/'; 044 private static final char BACKSLASH_CHAR = '\\'; 045 046 /** 047 * Perform a series of substitutions. The substitions 048 * are performed by replacing ${variable} in the target 049 * string with the value of provided by the key "variable" 050 * in the provided hashtable. 051 * 052 * @param argStr the argument string to be processed 053 * @param vars name/value pairs used for substitution 054 * @param isLenient ignore a key not found in vars? 055 * @return String target string with replacements. 056 */ 057 public static StringBuffer stringSubstitution(String argStr, Map vars, boolean isLenient) { 058 059 StringBuffer argBuf = new StringBuffer(); 060 061 if (argStr == null || argStr.length() == 0) { 062 return argBuf; 063 } 064 065 if (vars == null || vars.size() == 0) { 066 return argBuf.append(argStr); 067 } 068 069 int argStrLength = argStr.length(); 070 071 for (int cIdx = 0; cIdx < argStrLength;) { 072 073 char ch = argStr.charAt(cIdx); 074 char del = ' '; 075 076 switch (ch) { 077 078 case '$': 079 StringBuffer nameBuf = new StringBuffer(); 080 del = argStr.charAt(cIdx + 1); 081 if (del == '{') { 082 cIdx++; 083 084 for (++cIdx; cIdx < argStr.length(); ++cIdx) { 085 ch = argStr.charAt(cIdx); 086 if (ch == '_' || ch == '.' || ch == '-' || ch == '+' || Character.isLetterOrDigit(ch)) 087 nameBuf.append(ch); 088 else 089 break; 090 } 091 092 if (nameBuf.length() > 0) { 093 Object temp = vars.get(nameBuf.toString()); 094 String value = (temp != null ? temp.toString() : null); 095 096 if (value != null) { 097 argBuf.append(value); 098 } else { 099 if (isLenient) { 100 // just append the unresolved variable declaration 101 argBuf.append("${").append(nameBuf.toString()).append("}"); 102 } else { 103 // complain that no variable was found 104 throw new RuntimeException("No value found for : " + nameBuf); 105 } 106 } 107 108 del = argStr.charAt(cIdx); 109 110 if (del != '}') { 111 throw new RuntimeException("Delimiter not found for : " + nameBuf); 112 } 113 } 114 115 cIdx++; 116 } else { 117 argBuf.append(ch); 118 ++cIdx; 119 } 120 121 break; 122 123 default: 124 argBuf.append(ch); 125 ++cIdx; 126 break; 127 } 128 } 129 130 return argBuf; 131 } 132 133 /** 134 * Split a string into an array of strings based 135 * on a separator. 136 * 137 * @param input what to split 138 * @param splitChar what to split on 139 * @return the array of strings 140 */ 141 public static String[] split(String input, String splitChar) { 142 StringTokenizer tokens = new StringTokenizer(input, splitChar); 143 List strList = new ArrayList(); 144 while (tokens.hasMoreTokens()) { 145 strList.add(tokens.nextToken()); 146 } 147 return (String[]) strList.toArray(new String[strList.size()]); 148 } 149 150 /** 151 * Fixes the file sperator char for the target platform 152 * using the following replacement. 153 * 154 * <ul> 155 * <li> '/' ==> File.separatorChar 156 * <li> '\\' ==> File.separatorChar 157 * </ul> 158 * 159 * @param arg the argument to fix 160 * @return the transformed argument 161 */ 162 public static String fixFileSeparatorChar(String arg) { 163 return arg.replace(SLASH_CHAR, File.separatorChar).replace( 164 BACKSLASH_CHAR, File.separatorChar); 165 } 166 167 /** 168 * Concatenates an array of string using a separator. 169 * 170 * @param strings the strings to concatenate 171 * @param separator the separator between two strings 172 * @return the concatened strings 173 */ 174 public static String toString(String[] strings, String separator) { 175 StringBuffer sb = new StringBuffer(); 176 for (int i = 0; i < strings.length; i++) { 177 if (i > 0) { 178 sb.append(separator); 179 } 180 sb.append(strings[i]); 181 } 182 return sb.toString(); 183 } 184 185 /** 186 * Put quotes around the given String if necessary. 187 * <p> 188 * If the argument doesn't include spaces or quotes, return it as is. If it 189 * contains double quotes, use single quotes - else surround the argument by 190 * double quotes. 191 * </p> 192 * 193 * @param argument the argument to be quoted 194 * @return the quoted argument 195 * @throws IllegalArgumentException If argument contains both types of quotes 196 */ 197 public static String quoteArgument(final String argument) { 198 199 String cleanedArgument = argument.trim(); 200 201 while(cleanedArgument.startsWith(SINGLE_QUOTE) || cleanedArgument.startsWith(DOUBLE_QUOTE)) { 202 cleanedArgument = cleanedArgument.substring(1); 203 } 204 while(cleanedArgument.endsWith(SINGLE_QUOTE) || cleanedArgument.endsWith(DOUBLE_QUOTE)) { 205 cleanedArgument = cleanedArgument.substring(0, cleanedArgument.length() - 1); 206 } 207 208 final StringBuffer buf = new StringBuffer(); 209 if (cleanedArgument.indexOf(DOUBLE_QUOTE) > -1) { 210 if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1) { 211 throw new IllegalArgumentException( 212 "Can't handle single and double quotes in same argument"); 213 } else { 214 return buf.append(SINGLE_QUOTE).append(cleanedArgument).append( 215 SINGLE_QUOTE).toString(); 216 } 217 } else if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1 218 || cleanedArgument.indexOf(" ") > -1) { 219 return buf.append(DOUBLE_QUOTE).append(cleanedArgument).append( 220 DOUBLE_QUOTE).toString(); 221 } else { 222 return cleanedArgument; 223 } 224 } 225 226 /** 227 * Determines if this is a quoted argumented - either single or 228 * double quoted. 229 * 230 * @param argument the argument to check 231 * @return true when the argument is quoted 232 */ 233 public static boolean isQuoted(final String argument) { 234 return ( argument.startsWith( SINGLE_QUOTE ) || argument.startsWith( DOUBLE_QUOTE ) ) && 235 ( argument.endsWith( SINGLE_QUOTE ) || argument.endsWith( DOUBLE_QUOTE ) ); 236 } 237 }