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 1677406 2015-05-03 14:27:31Z britter $ 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 else 158 { 159 Option opt = options.getOption(matchingOpts.get(0)); 160 processOptionToken("-" + opt.getLongOpt(), stopAtNonOption); 161 } 162 } 163 // requires bursting 164 else 165 { 166 burstToken(token, stopAtNonOption); 167 } 168 } 169 else 170 { 171 processNonOptionToken(token, stopAtNonOption); 172 } 173 174 gobble(iter); 175 } 176 177 return tokens.toArray(new String[tokens.size()]); 178 } 179 180 /** 181 * Adds the remaining tokens to the processed tokens list. 182 * 183 * @param iter An iterator over the remaining tokens 184 */ 185 private void gobble(Iterator<String> iter) 186 { 187 if (eatTheRest) 188 { 189 while (iter.hasNext()) 190 { 191 tokens.add(iter.next()); 192 } 193 } 194 } 195 196 /** 197 * Add the special token "<b>--</b>" and the current <code>value</code> 198 * to the processed tokens list. Then add all the remaining 199 * <code>argument</code> values to the processed tokens list. 200 * 201 * @param value The current token 202 */ 203 private void processNonOptionToken(String value, boolean stopAtNonOption) 204 { 205 if (stopAtNonOption && (currentOption == null || !currentOption.hasArg())) 206 { 207 eatTheRest = true; 208 tokens.add("--"); 209 } 210 211 tokens.add(value); 212 } 213 214 /** 215 * <p>If an {@link Option} exists for <code>token</code> then 216 * add the token to the processed list.</p> 217 * 218 * <p>If an {@link Option} does not exist and <code>stopAtNonOption</code> 219 * is set then add the remaining tokens to the processed tokens list 220 * directly.</p> 221 * 222 * @param token The current option token 223 * @param stopAtNonOption Specifies whether flattening should halt 224 * at the first non option. 225 */ 226 private void processOptionToken(String token, boolean stopAtNonOption) 227 { 228 if (stopAtNonOption && !options.hasOption(token)) 229 { 230 eatTheRest = true; 231 } 232 233 if (options.hasOption(token)) 234 { 235 currentOption = options.getOption(token); 236 } 237 238 tokens.add(token); 239 } 240 241 /** 242 * Breaks <code>token</code> into its constituent parts 243 * using the following algorithm. 244 * 245 * <ul> 246 * <li>ignore the first character ("<b>-</b>")</li> 247 * <li>foreach remaining character check if an {@link Option} 248 * exists with that id.</li> 249 * <li>if an {@link Option} does exist then add that character 250 * prepended with "<b>-</b>" to the list of processed tokens.</li> 251 * <li>if the {@link Option} can have an argument value and there 252 * are remaining characters in the token then add the remaining 253 * characters as a token to the list of processed tokens.</li> 254 * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> 255 * <code>stopAtNonOption</code> <b>IS</b> set then add the special token 256 * "<b>--</b>" followed by the remaining characters and also 257 * the remaining tokens directly to the processed tokens list.</li> 258 * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> 259 * <code>stopAtNonOption</code> <b>IS NOT</b> set then add that 260 * character prepended with "<b>-</b>".</li> 261 * </ul> 262 * 263 * @param token The current token to be <b>burst</b> 264 * @param stopAtNonOption Specifies whether to stop processing 265 * at the first non-Option encountered. 266 */ 267 protected void burstToken(String token, boolean stopAtNonOption) 268 { 269 for (int i = 1; i < token.length(); i++) 270 { 271 String ch = String.valueOf(token.charAt(i)); 272 273 if (options.hasOption(ch)) 274 { 275 tokens.add("-" + ch); 276 currentOption = options.getOption(ch); 277 278 if (currentOption.hasArg() && token.length() != i + 1) 279 { 280 tokens.add(token.substring(i + 1)); 281 282 break; 283 } 284 } 285 else if (stopAtNonOption) 286 { 287 processNonOptionToken(token.substring(i), true); 288 break; 289 } 290 else 291 { 292 tokens.add(token); 293 break; 294 } 295 } 296 } 297}