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.commons.cli; 019 020 import java.io.File; 021 import java.io.FileInputStream; 022 import java.net.URL; 023 import java.util.Date; 024 025 /** 026 * <p> 027 * Allows Options to be created from a single String. 028 * The pattern contains various single character flags and via 029 * an optional punctuation character, their expected type. 030 * </p> 031 * 032 * <table border="1"> 033 * <tr><td>a</td><td>-a flag</td></tr> 034 * <tr><td>b@</td><td>-b [classname]</td></tr> 035 * <tr><td>c></td><td>-c [filename]</td></tr> 036 * <tr><td>d+</td><td>-d [classname] (creates object via empty contructor)</td></tr> 037 * <tr><td>e%</td><td>-e [number] (creates Double/Long instance depeding on existing of a '.')</td></tr> 038 * <tr><td>f/</td><td>-f [url]</td></tr> 039 * <tr><td>g:</td><td>-g [string]</td></tr> 040 * </table> 041 * 042 * <p> 043 * For example, the following allows command line flags of '-v -p string-value -f /dir/file'. 044 * The exclamation mark precede a mandatory option. 045 * </p> 046 * <code>Options options = PatternOptionBuilder.parsePattern("vp:!f/");</code> 047 * 048 * <p> 049 * TODO These need to break out to OptionType and also 050 * to be pluggable. 051 * </p> 052 * 053 * @version $Revision: 734339 $, $Date: 2009-01-13 21:56:47 -0800 (Tue, 13 Jan 2009) $ 054 */ 055 public class PatternOptionBuilder 056 { 057 /** String class */ 058 public static final Class STRING_VALUE = String.class; 059 060 /** Object class */ 061 public static final Class OBJECT_VALUE = Object.class; 062 063 /** Number class */ 064 public static final Class NUMBER_VALUE = Number.class; 065 066 /** Date class */ 067 public static final Class DATE_VALUE = Date.class; 068 069 /** Class class */ 070 public static final Class CLASS_VALUE = Class.class; 071 072 /// can we do this one?? 073 // is meant to check that the file exists, else it errors. 074 // ie) it's for reading not writing. 075 076 /** FileInputStream class */ 077 public static final Class EXISTING_FILE_VALUE = FileInputStream.class; 078 079 /** File class */ 080 public static final Class FILE_VALUE = File.class; 081 082 /** File array class */ 083 public static final Class FILES_VALUE = File[].class; 084 085 /** URL class */ 086 public static final Class URL_VALUE = URL.class; 087 088 /** 089 * Retrieve the class that <code>ch</code> represents. 090 * 091 * @param ch the specified character 092 * @return The class that <code>ch</code> represents 093 */ 094 public static Object getValueClass(char ch) 095 { 096 switch (ch) 097 { 098 case '@': 099 return PatternOptionBuilder.OBJECT_VALUE; 100 case ':': 101 return PatternOptionBuilder.STRING_VALUE; 102 case '%': 103 return PatternOptionBuilder.NUMBER_VALUE; 104 case '+': 105 return PatternOptionBuilder.CLASS_VALUE; 106 case '#': 107 return PatternOptionBuilder.DATE_VALUE; 108 case '<': 109 return PatternOptionBuilder.EXISTING_FILE_VALUE; 110 case '>': 111 return PatternOptionBuilder.FILE_VALUE; 112 case '*': 113 return PatternOptionBuilder.FILES_VALUE; 114 case '/': 115 return PatternOptionBuilder.URL_VALUE; 116 } 117 118 return null; 119 } 120 121 /** 122 * Returns whether <code>ch</code> is a value code, i.e. 123 * whether it represents a class in a pattern. 124 * 125 * @param ch the specified character 126 * @return true if <code>ch</code> is a value code, otherwise false. 127 */ 128 public static boolean isValueCode(char ch) 129 { 130 return ch == '@' 131 || ch == ':' 132 || ch == '%' 133 || ch == '+' 134 || ch == '#' 135 || ch == '<' 136 || ch == '>' 137 || ch == '*' 138 || ch == '/' 139 || ch == '!'; 140 } 141 142 /** 143 * Returns the {@link Options} instance represented by <code>pattern</code>. 144 * 145 * @param pattern the pattern string 146 * @return The {@link Options} instance 147 */ 148 public static Options parsePattern(String pattern) 149 { 150 char opt = ' '; 151 boolean required = false; 152 Object type = null; 153 154 Options options = new Options(); 155 156 for (int i = 0; i < pattern.length(); i++) 157 { 158 char ch = pattern.charAt(i); 159 160 // a value code comes after an option and specifies 161 // details about it 162 if (!isValueCode(ch)) 163 { 164 if (opt != ' ') 165 { 166 OptionBuilder.hasArg(type != null); 167 OptionBuilder.isRequired(required); 168 OptionBuilder.withType(type); 169 170 // we have a previous one to deal with 171 options.addOption(OptionBuilder.create(opt)); 172 required = false; 173 type = null; 174 opt = ' '; 175 } 176 177 opt = ch; 178 } 179 else if (ch == '!') 180 { 181 required = true; 182 } 183 else 184 { 185 type = getValueClass(ch); 186 } 187 } 188 189 if (opt != ' ') 190 { 191 OptionBuilder.hasArg(type != null); 192 OptionBuilder.isRequired(required); 193 OptionBuilder.withType(type); 194 195 // we have a final one to deal with 196 options.addOption(OptionBuilder.create(opt)); 197 } 198 199 return options; 200 } 201 }