    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&gt;</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    }