1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.cli;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.net.URL;
23 import java.util.Date;
24
25 /**
26 * Allows Options to be created from a single String.
27 * The pattern contains various single character flags and via
28 * an optional punctuation character, their expected type.
29 * <p>
30 * <table border="1">
31 * <tr><td>a</td><td>-a flag</td></tr>
32 * <tr><td>b@</td><td>-b [classname]</td></tr>
33 * <tr><td>c></td><td>-c [filename]</td></tr>
34 * <tr><td>d+</td><td>-d [classname] (creates object via empty constructor)</td></tr>
35 * <tr><td>e%</td><td>-e [number] (creates Double/Long instance depending on existing of a '.')</td></tr>
36 * <tr><td>f/</td><td>-f [url]</td></tr>
37 * <tr><td>g:</td><td>-g [string]</td></tr>
38 * </table>
39 * <p>
40 * For example, the following allows command line flags of '-v -p string-value -f /dir/file'.
41 * The exclamation mark precede a mandatory option.
42 *
43 * <pre>
44 * Options options = PatternOptionBuilder.parsePattern("vp:!f/");
45 * </pre>
46 *
47 * <p>
48 * TODO These need to break out to OptionType and also to be pluggable.
49 *
50 * @version $Id: PatternOptionBuilder.java 1447005 2013-02-17 11:11:06Z tn $
51 */
52 public class PatternOptionBuilder
53 {
54 /** String class */
55 public static final Class<String> STRING_VALUE = String.class;
56
57 /** Object class */
58 public static final Class<Object> OBJECT_VALUE = Object.class;
59
60 /** Number class */
61 public static final Class<Number> NUMBER_VALUE = Number.class;
62
63 /** Date class */
64 public static final Class<Date> DATE_VALUE = Date.class;
65
66 /** Class class */
67 public static final Class<?> CLASS_VALUE = Class.class;
68
69 /// can we do this one??
70 // is meant to check that the file exists, else it errors.
71 // ie) it's for reading not writing.
72
73 /** FileInputStream class */
74 public static final Class<FileInputStream> EXISTING_FILE_VALUE = FileInputStream.class;
75
76 /** File class */
77 public static final Class<File> FILE_VALUE = File.class;
78
79 /** File array class */
80 public static final Class<File[]> FILES_VALUE = File[].class;
81
82 /** URL class */
83 public static final Class<URL> URL_VALUE = URL.class;
84
85 /**
86 * Retrieve the class that <code>ch</code> represents.
87 *
88 * @param ch the specified character
89 * @return The class that <code>ch</code> represents
90 */
91 public static Object getValueClass(char ch)
92 {
93 switch (ch)
94 {
95 case '@':
96 return PatternOptionBuilder.OBJECT_VALUE;
97 case ':':
98 return PatternOptionBuilder.STRING_VALUE;
99 case '%':
100 return PatternOptionBuilder.NUMBER_VALUE;
101 case '+':
102 return PatternOptionBuilder.CLASS_VALUE;
103 case '#':
104 return PatternOptionBuilder.DATE_VALUE;
105 case '<':
106 return PatternOptionBuilder.EXISTING_FILE_VALUE;
107 case '>':
108 return PatternOptionBuilder.FILE_VALUE;
109 case '*':
110 return PatternOptionBuilder.FILES_VALUE;
111 case '/':
112 return PatternOptionBuilder.URL_VALUE;
113 }
114
115 return null;
116 }
117
118 /**
119 * Returns whether <code>ch</code> is a value code, i.e.
120 * whether it represents a class in a pattern.
121 *
122 * @param ch the specified character
123 * @return true if <code>ch</code> is a value code, otherwise false.
124 */
125 public static boolean isValueCode(char ch)
126 {
127 return ch == '@'
128 || ch == ':'
129 || ch == '%'
130 || ch == '+'
131 || ch == '#'
132 || ch == '<'
133 || ch == '>'
134 || ch == '*'
135 || ch == '/'
136 || ch == '!';
137 }
138
139 /**
140 * Returns the {@link Options} instance represented by <code>pattern</code>.
141 *
142 * @param pattern the pattern string
143 * @return The {@link Options} instance
144 */
145 public static Options parsePattern(String pattern)
146 {
147 char opt = ' ';
148 boolean required = false;
149 Class<?> type = null;
150
151 Options options = new Options();
152
153 for (int i = 0; i < pattern.length(); i++)
154 {
155 char ch = pattern.charAt(i);
156
157 // a value code comes after an option and specifies
158 // details about it
159 if (!isValueCode(ch))
160 {
161 if (opt != ' ')
162 {
163 final Option option = Option.builder(String.valueOf(opt))
164 .hasArg(type != null)
165 .required(required)
166 .type(type)
167 .build();
168
169 // we have a previous one to deal with
170 options.addOption(option);
171 required = false;
172 type = null;
173 opt = ' ';
174 }
175
176 opt = ch;
177 }
178 else if (ch == '!')
179 {
180 required = true;
181 }
182 else
183 {
184 type = (Class<?>) getValueClass(ch);
185 }
186 }
187
188 if (opt != ' ')
189 {
190 final Option option = Option.builder(String.valueOf(opt))
191 .hasArg(type != null)
192 .required(required)
193 .type(type)
194 .build();
195
196 // we have a final one to deal with
197 options.addOption(option);
198 }
199
200 return options;
201 }
202 }