1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.HashMap; 22 import java.util.HashSet; 23 import java.util.Set; 24 import java.util.regex.Matcher; 25 import java.util.regex.Pattern; 26 27 /** 28 * CommandParser is responsible for parsing command line arguments. To get 29 * action, option or values easy via functions. 30 * For example: 31 * <ul> 32 * <li> CommandParser cp = CommandParser.parse("start -plan test_plan") 33 * <li> cp.getAction() will get "start" 34 * <li> cp.getValue("-plan") will get "test_plan" 35 * <li> cp.containsKey("-noplan") will get null 36 * </ul> 37 * 38 */ 39 public class CommandParser { 40 41 /** 42 * The hash map mapping the options and option values. 43 */ 44 private HashMap<String, String> mValues = new HashMap<String, String>(); 45 46 /** 47 * The action the user chose to ask CTS host to take. 48 */ 49 private String mAction; 50 private ArrayList<String> mActionValues = new ArrayList<String>(); 51 private int mArgLength; 52 private static final String COMMAND_PARSE_EXPRESSION = "(((\\\\\\s)|[\\S&&[^\"]])+|\".+\")"; 53 54 private static Set<String> sOptionsSet = new HashSet<String>(Arrays.asList( 55 CTSCommand.OPTION_CFG, CTSCommand.OPTION_PACKAGE, CTSCommand.OPTION_PLAN, 56 CTSCommand.OPTION_DEVICE, CTSCommand.OPTION_RESULT, CTSCommand.OPTION_E, 57 CTSCommand.OPTION_SESSION, CTSCommand.OPTION_TEST, CTSCommand.OPTION_DERIVED_PLAN)); 58 private static HashMap<String, String> sOptionMap = new HashMap<String, String>(); 59 static { 60 final String[] keys = new String[] { 61 CTSCommand.OPTION_CFG, 62 CTSCommand.OPTION_P, 63 CTSCommand.OPTION_PACKAGE, 64 CTSCommand.OPTION_PLAN, 65 CTSCommand.OPTION_D, 66 CTSCommand.OPTION_DEVICE, 67 CTSCommand.OPTION_R, 68 CTSCommand.OPTION_RESULT, 69 CTSCommand.OPTION_E, 70 CTSCommand.OPTION_S, 71 CTSCommand.OPTION_SESSION, 72 CTSCommand.OPTION_T, 73 CTSCommand.OPTION_TEST, 74 CTSCommand.OPTION_DERIVED_PLAN}; 75 76 final String[] values = new String[] { 77 CTSCommand.OPTION_CFG, 78 CTSCommand.OPTION_PACKAGE, 79 CTSCommand.OPTION_PACKAGE, 80 CTSCommand.OPTION_PLAN, 81 CTSCommand.OPTION_DEVICE, 82 CTSCommand.OPTION_DEVICE, 83 CTSCommand.OPTION_RESULT, 84 CTSCommand.OPTION_RESULT, 85 CTSCommand.OPTION_E, 86 CTSCommand.OPTION_SESSION, 87 CTSCommand.OPTION_SESSION, 88 CTSCommand.OPTION_TEST, 89 CTSCommand.OPTION_TEST, 90 CTSCommand.OPTION_DERIVED_PLAN}; 91 92 for (int i = 0; i < keys.length; i++) { sOptionMap.put(keys[i], values[i])93 sOptionMap.put(keys[i], values[i]); 94 } 95 } 96 97 /** 98 * Parse the command line into array of argument. 99 * 100 * @param line The original command line. 101 * @return The command container. 102 */ parse(final String line)103 public static CommandParser parse(final String line) 104 throws UnknownCommandException, CommandNotFoundException { 105 ArrayList<String> arglist = new ArrayList<String>(); 106 107 Pattern p = Pattern.compile(COMMAND_PARSE_EXPRESSION); 108 Matcher m = p.matcher(line); 109 while (m.find()) { 110 arglist.add(m.group(1)); 111 } 112 CommandParser cp = new CommandParser(); 113 if (arglist.size() == 0) { 114 throw new CommandNotFoundException("No command"); 115 } 116 cp.parse(arglist); 117 return cp; 118 } 119 120 /** 121 * Parse the argument list. 122 * 123 * @param arglist The argument list. 124 */ parse(ArrayList<String> arglist)125 private void parse(ArrayList<String> arglist) 126 throws UnknownCommandException { 127 mArgLength = arglist.size(); 128 int currentArgIndex = 0; 129 mAction = arglist.get(currentArgIndex).toLowerCase(); 130 String originalOption = null; 131 String option = null; 132 133 // parse action values 134 while (++currentArgIndex < arglist.size()) { 135 originalOption = arglist.get(currentArgIndex).trim(); 136 if (originalOption.startsWith("-")) { 137 if (isNumber(originalOption)) { 138 mActionValues.add(originalOption); 139 } else { 140 --currentArgIndex; 141 break; 142 } 143 } else { 144 mActionValues.add(originalOption); 145 } 146 } 147 148 // parse option 149 while (++currentArgIndex < arglist.size()) { 150 originalOption = arglist.get(currentArgIndex).trim().toLowerCase(); 151 option = originalOption; 152 if (!option.startsWith("-")) { 153 throw new UnknownCommandException( 154 "Option should start with '-'"); 155 } 156 157 option = inputToOption(option); 158 if (!sOptionsSet.contains(option)) { 159 throw new UnknownCommandException("Unknown option :" 160 + originalOption); 161 } 162 163 if (mValues.containsKey(option)) { 164 throw new UnknownCommandException("Duplicate option: " 165 + originalOption); 166 } 167 168 if (currentArgIndex + 1 == arglist.size()) { 169 mValues.put(option, ""); 170 continue; 171 } 172 173 String value = arglist.get(++currentArgIndex).trim(); 174 if (value.startsWith("-")) { 175 if (!isNumber(value)) { 176 value = ""; 177 currentArgIndex--; 178 } 179 } 180 181 mValues.put(option, value); 182 } 183 } 184 185 /** 186 * Translate the input to option. 187 * 188 * @param option The option typed in. 189 * @return The option found. 190 */ inputToOption(String option)191 private String inputToOption(String option) throws UnknownCommandException { 192 String op = sOptionMap.get(option); 193 if (op == null) { 194 throw new UnknownCommandException("Unknow option " + option); 195 } 196 197 return op; 198 } 199 200 /** 201 * Check if the option is a number. 202 * 203 * @param option The option. 204 * @return If the option is a number, return true; else, return false. 205 */ isNumber(String option)206 private boolean isNumber(String option) { 207 try { 208 Integer.parseInt(option); 209 return true; 210 } catch (Exception e) { 211 return false; 212 } 213 } 214 215 /** 216 * Get the arguments size. 217 * 218 * @return The argument size. 219 */ getArgSize()220 public int getArgSize() { 221 return mArgLength; 222 } 223 224 /** 225 * Get the action. 226 * 227 * @return The action. 228 */ getAction()229 public String getAction() { 230 return mAction; 231 } 232 233 /** 234 * Get the option size. 235 * 236 * @return The option size. 237 */ getOptionSize()238 public int getOptionSize() { 239 return mValues.size(); 240 } 241 242 /** 243 * Get command option by hash key from parsed argument list. 244 * 245 * @param key The key. 246 * @return The value according to the key. 247 */ getValue(String key)248 public String getValue(String key) { 249 if (mValues.containsKey(key)) { 250 return mValues.get(key); 251 } else { 252 return null; 253 } 254 } 255 256 /** 257 * Check if option list contains the key. 258 * 259 * @param key The key. 260 * @return If containing the key, return true; else, return false. 261 */ containsKey(String key)262 public boolean containsKey(String key) { 263 return mValues.containsKey(key); 264 } 265 266 /** 267 * Get all of the option keys. 268 * 269 * @return All of the option keys. 270 */ getOptionKeys()271 public Set<String> getOptionKeys() { 272 return mValues.keySet(); 273 } 274 275 /** 276 * Get action list. 277 * 278 * @return The action list. 279 */ getActionValues()280 public ArrayList<String> getActionValues() { 281 return mActionValues; 282 } 283 284 /** 285 * Remove a specific key. 286 * 287 * @param key The key to be removed. 288 */ removeKey(String key)289 public void removeKey(String key) { 290 mValues.remove(key); 291 } 292 293 } 294