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 018package org.apache.commons.cli; 019 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Iterator; 023import java.util.List; 024 025/** 026 * The class PosixParser provides an implementation of the 027 * {@link Parser#flatten(Options,String[],boolean) flatten} method. 028 * 029 * @version $Id: PosixParser.java 1677451 2015-05-03 17:09:29Z ggregory $ 030 * @deprecated since 1.3, use the {@link DefaultParser} instead 031 */ 032@Deprecated 033public class PosixParser extends Parser 034{ 035 /** holder for flattened tokens */ 036 private final List<String> tokens = new ArrayList<String>(); 037 038 /** specifies if bursting should continue */ 039 private boolean eatTheRest; 040 041 /** holder for the current option */ 042 private Option currentOption; 043 044 /** the command line Options */ 045 private Options options; 046 047 /** 048 * Resets the members to their original state i.e. remove 049 * all of <code>tokens</code> entries and set <code>eatTheRest</code> 050 * to false. 051 */ 052 private void init() 053 { 054 eatTheRest = false; 055 tokens.clear(); 056 } 057 058 /** 059 * <p>An implementation of {@link Parser}'s abstract 060 * {@link Parser#flatten(Options,String[],boolean) flatten} method.</p> 061 * 062 * <p>The following are the rules used by this flatten method.</p> 063 * <ol> 064 * <li>if <code>stopAtNonOption</code> is <b>true</b> then do not 065 * burst anymore of <code>arguments</code> entries, just add each 066 * successive entry without further processing. Otherwise, ignore 067 * <code>stopAtNonOption</code>.</li> 068 * <li>if the current <code>arguments</code> entry is "<b>--</b>" 069 * just add the entry to the list of processed tokens</li> 070 * <li>if the current <code>arguments</code> entry is "<b>-</b>" 071 * just add the entry to the list of processed tokens</li> 072 * <li>if the current <code>arguments</code> entry is two characters 073 * in length and the first character is "<b>-</b>" then check if this 074 * is a valid {@link Option} id. If it is a valid id, then add the 075 * entry to the list of processed tokens and set the current {@link Option} 076 * member. If it is not a valid id and <code>stopAtNonOption</code> 077 * is true, then the remaining entries are copied to the list of 078 * processed tokens. Otherwise, the current entry is ignored.</li> 079 * <li>if the current <code>arguments</code> entry is more than two 080 * characters in length and the first character is "<b>-</b>" then 081 * we need to burst the entry to determine its constituents. For more 082 * information on the bursting algorithm see 083 * {@link PosixParser#burstToken(String, boolean) burstToken}.</li> 084 * <li>if the current <code>arguments</code> entry is not handled 085 * by any of the previous rules, then the entry is added to the list 086 * of processed tokens.</li> 087 * </ol> 088 * 089 * @param options The command line {@link Options} 090 * @param arguments The command line arguments to be parsed 091 * @param stopAtNonOption Specifies whether to stop flattening 092 * when an non option is found. 093 * @return The flattened <code>arguments</code> String array. 094 */ 095 @Override 096 protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException 097 { 098 init(); 099 this.options = options; 100 101 // an iterator for the command line tokens 102 Iterator<String> iter = Arrays.asList(arguments).iterator(); 103 104 // process each command line token 105 while (iter.hasNext()) 106 { 107 // get the next command line token 108 String token = iter.next(); 109 110 // single or double hyphen 111 if ("-".equals(token) || "--".equals(token)) 112 { 113 tokens.add(token); 114 } 115 116 // handle long option --foo or --foo=bar 117 else if (token.startsWith("--")) 118 { 119 int pos = token.indexOf('='); 120 String opt = pos == -1 ? token : token.substring(0, pos); // --foo 121 122 List<String> matchingOpts = options.getMatchingOptions(opt); 123 124 if (matchingOpts.isEmpty()) 125 { 126 processNonOptionToken(token, stopAtNonOption); 127 } 128 else if (matchingOpts.size() > 1) 129 { 130 throw new AmbiguousOptionException(opt, matchingOpts); 131 } 132 else 133 { 134 currentOption = options.getOption(matchingOpts.get(0)); 135 136 tokens.add("--" + currentOption.getLongOpt()); 137 if (pos != -1) 138 { 139 tokens.add(token.substring(pos + 1)); 140 } 141 } 142 } 143 144 else if (token.startsWith("-")) 145 { 146 if (token.length() == 2 || options.hasOption(token)) 147 { 148 processOptionToken(token, stopAtNonOption); 149 } 150 else if (!options.getMatchingOptions(token).isEmpty()) 151 { 152 List<String> matchingOpts = options.getMatchingOptions(token); 153 if (matchingOpts.size() > 1) 154 { 155 throw new AmbiguousOptionException(token, matchingOpts); 156 } 157 Option opt = options.getOption(matchingOpts.get(0)); 158 processOptionToken("-" + opt.getLongOpt(), stopAtNonOption); 159 } 160 // requires bursting 161 else 162 { 163 burstToken(token, stopAtNonOption); 164 } 165 } 166 else 167 { 168 processNonOptionToken(token, stopAtNonOption); 169 } 170 171 gobble(iter); 172 } 173 174 return tokens.toArray(new String[tokens.size()]); 175 } 176 177 /** 178 * Adds the remaining tokens to the processed tokens list. 179 * 180 * @param iter An iterator over the remaining tokens 181 */ 182 private void gobble(Iterator<String> iter) 183 { 184 if (eatTheRest) 185 { 186 while (iter.hasNext()) 187 { 188 tokens.add(iter.next()); 189 } 190 } 191 } 192 193 /** 194 * Add the special token "<b>--</b>" and the current <code>value</code> 195 * to the processed tokens list. Then add all the remaining 196 * <code>argument</code> values to the processed tokens list. 197 * 198 * @param value The current token 199 */ 200 private void processNonOptionToken(String value, boolean stopAtNonOption) 201 { 202 if (stopAtNonOption && (currentOption == null || !currentOption.hasArg())) 203 { 204 eatTheRest = true; 205 tokens.add("--"); 206 } 207 208 tokens.add(value); 209 } 210 211 /** 212 * <p>If an {@link Option} exists for <code>token</code> then 213 * add the token to the processed list.</p> 214 * 215 * <p>If an {@link Option} does not exist and <code>stopAtNonOption</code> 216 * is set then add the remaining tokens to the processed tokens list 217 * directly.</p> 218 * 219 * @param token The current option token 220 * @param stopAtNonOption Specifies whether flattening should halt 221 * at the first non option. 222 */ 223 private void processOptionToken(String token, boolean stopAtNonOption) 224 { 225 if (stopAtNonOption && !options.hasOption(token)) 226 { 227 eatTheRest = true; 228 } 229 230 if (options.hasOption(token)) 231 { 232 currentOption = options.getOption(token); 233 } 234 235 tokens.add(token); 236 } 237 238 /** 239 * Breaks <code>token</code> into its constituent parts 240 * using the following algorithm. 241 * 242 * <ul> 243 * <li>ignore the first character ("<b>-</b>")</li> 244 * <li>foreach remaining character check if an {@link Option} 245 * exists with that id.</li> 246 * <li>if an {@link Option} does exist then add that character 247 * prepended with "<b>-</b>" to the list of processed tokens.</li> 248 * <li>if the {@link Option} can have an argument value and there 249 * are remaining characters in the token then add the remaining 250 * characters as a token to the list of processed tokens.</li> 251 * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> 252 * <code>stopAtNonOption</code> <b>IS</b> set then add the special token 253 * "<b>--</b>" followed by the remaining characters and also 254 * the remaining tokens directly to the processed tokens list.</li> 255 * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> 256 * <code>stopAtNonOption</code> <b>IS NOT</b> set then add that 257 * character prepended with "<b>-</b>".</li> 258 * </ul> 259 * 260 * @param token The current token to be <b>burst</b> 261 * @param stopAtNonOption Specifies whether to stop processing 262 * at the first non-Option encountered. 263 */ 264 protected void burstToken(String token, boolean stopAtNonOption) 265 { 266 for (int i = 1; i < token.length(); i++) 267 { 268 String ch = String.valueOf(token.charAt(i)); 269 270 if (options.hasOption(ch)) 271 { 272 tokens.add("-" + ch); 273 currentOption = options.getOption(ch); 274 275 if (currentOption.hasArg() && token.length() != i + 1) 276 { 277 tokens.add(token.substring(i + 1)); 278 279 break; 280 } 281 } 282 else if (stopAtNonOption) 283 { 284 processNonOptionToken(token.substring(i), true); 285 break; 286 } 287 else 288 { 289 tokens.add(token); 290 break; 291 } 292 } 293 } 294}