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 }