View Javadoc

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   * <p>
27   * Allows Options to be created from a single String.
28   * The pattern contains various single character flags and via
29   * an optional punctuation character, their expected type.
30   * </p>
31   *
32   * <table border="1">
33   * <tr><td>a</td><td>-a flag</td></tr>
34   * <tr><td>b@</td><td>-b [classname]</td></tr>
35   * <tr><td>c&gt;</td><td>-c [filename]</td></tr>
36   * <tr><td>d+</td><td>-d [classname] (creates object via empty contructor)</td></tr>
37   * <tr><td>e%</td><td>-e [number] (creates Double/Long instance depeding on existing of a '.')</td></tr>
38   * <tr><td>f/</td><td>-f [url]</td></tr>
39   * <tr><td>g:</td><td>-g [string]</td></tr>
40   * </table>
41   *
42   * <p>
43   * For example, the following allows command line flags of '-v -p string-value -f /dir/file'.
44   * The exclamation mark precede a mandatory option.
45   * </p>
46   * <code>Options options = PatternOptionBuilder.parsePattern("vp:!f/");</code>
47   *
48   * <p>
49   * TODO These need to break out to OptionType and also
50   * to be pluggable.
51   * </p>
52   *
53   * @version $Revision: 734339 $, $Date: 2009-01-14 05:56:47 +0000 (Wed, 14 Jan 2009) $
54   */
55  public class PatternOptionBuilder
56  {
57      /** String class */
58      public static final Class STRING_VALUE = String.class;
59  
60      /** Object class */
61      public static final Class OBJECT_VALUE = Object.class;
62  
63      /** Number class */
64      public static final Class NUMBER_VALUE = Number.class;
65  
66      /** Date class */
67      public static final Class DATE_VALUE = Date.class;
68  
69      /** Class class */
70      public static final Class CLASS_VALUE = Class.class;
71  
72      /// can we do this one??
73      // is meant to check that the file exists, else it errors.
74      // ie) it's for reading not writing.
75  
76      /** FileInputStream class */
77      public static final Class EXISTING_FILE_VALUE = FileInputStream.class;
78  
79      /** File class */
80      public static final Class FILE_VALUE = File.class;
81  
82      /** File array class */
83      public static final Class FILES_VALUE = File[].class;
84  
85      /** URL class */
86      public static final Class URL_VALUE = URL.class;
87  
88      /**
89       * Retrieve the class that <code>ch</code> represents.
90       *
91       * @param ch the specified character
92       * @return The class that <code>ch</code> represents
93       */
94      public static Object getValueClass(char ch)
95      {
96          switch (ch)
97          {
98              case '@':
99                  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 }