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    package org.apache.commons.cli2.option;
018    
019    import java.util.ArrayList;
020    import java.util.Collections;
021    import java.util.Comparator;
022    import java.util.List;
023    import java.util.ListIterator;
024    import java.util.Set;
025    
026    import org.apache.commons.cli2.Argument;
027    import org.apache.commons.cli2.DisplaySetting;
028    import org.apache.commons.cli2.Group;
029    import org.apache.commons.cli2.Option;
030    import org.apache.commons.cli2.OptionException;
031    import org.apache.commons.cli2.Parent;
032    import org.apache.commons.cli2.WriteableCommandLine;
033    
034    /**
035     * A base implementation of Parent providing limited ground work for further
036     * Parent implementations.
037     */
038    public abstract class ParentImpl
039        extends OptionImpl implements Parent {
040        private static final char NUL = '\0';
041        private final Group children;
042        private final Argument argument;
043        private final String description;
044    
045        protected ParentImpl(final Argument argument,
046                             final Group children,
047                             final String description,
048                             final int id,
049                             final boolean required) {
050            super(id, required);
051            this.children = children;
052            this.argument = argument;
053            this.description = description;
054        }
055    
056        /*
057         * (non-Javadoc)
058         *
059         * @see org.apache.commons.cli2.Option#process(org.apache.commons.cli2.CommandLine,
060         *      java.util.ListIterator)
061         */
062        public void process(final WriteableCommandLine commandLine,
063                            final ListIterator arguments)
064            throws OptionException {
065            if (argument != null) {
066                handleInitialSeparator(arguments, argument.getInitialSeparator());
067            }
068    
069            processParent(commandLine, arguments);
070    
071            if (argument != null) {
072                argument.processValues(commandLine, arguments, this);
073            }
074    
075            if ((children != null) && children.canProcess(commandLine, arguments)) {
076                children.process(commandLine, arguments);
077            }
078        }
079    
080        /*
081         * (non-Javadoc)
082         *
083         * @see org.apache.commons.cli2.Option#canProcess(java.lang.String)
084         */
085        public boolean canProcess(final WriteableCommandLine commandLine,
086                                  final String arg) {
087            final Set triggers = getTriggers();
088    
089            if (argument != null) {
090                final char separator = argument.getInitialSeparator();
091    
092                // if there is a valid separator character
093                if (separator != NUL) {
094                    final int initialIndex = arg.indexOf(separator);
095    
096                    // if there is a separator present
097                    if (initialIndex > 0) {
098                        return triggers.contains(arg.substring(0, initialIndex));
099                    }
100                }
101            }
102    
103            return triggers.contains(arg);
104        }
105    
106        /*
107         * (non-Javadoc)
108         *
109         * @see org.apache.commons.cli2.Option#prefixes()
110         */
111        public Set getPrefixes() {
112            return (children == null) ? Collections.EMPTY_SET : children.getPrefixes();
113        }
114    
115        /*
116         * (non-Javadoc)
117         *
118         * @see org.apache.commons.cli2.Option#validate(org.apache.commons.cli2.CommandLine)
119         */
120        public void validate(WriteableCommandLine commandLine)
121            throws OptionException {
122            if (commandLine.hasOption(this)) {
123                if (argument != null) {
124                    argument.validate(commandLine, this);
125                }
126    
127                if (children != null) {
128                    children.validate(commandLine);
129                }
130            }
131        }
132    
133        /*
134         * (non-Javadoc)
135         *
136         * @see org.apache.commons.cli2.Option#appendUsage(java.lang.StringBuffer,
137         *      java.util.Set, java.util.Comparator)
138         */
139        public void appendUsage(final StringBuffer buffer,
140                                final Set helpSettings,
141                                final Comparator comp) {
142            final boolean displayArgument =
143                (this.argument != null) &&
144                helpSettings.contains(DisplaySetting.DISPLAY_PARENT_ARGUMENT);
145            final boolean displayChildren =
146                (this.children != null) &&
147                helpSettings.contains(DisplaySetting.DISPLAY_PARENT_CHILDREN);
148    
149            if (displayArgument) {
150                buffer.append(' ');
151                argument.appendUsage(buffer, helpSettings, comp);
152            }
153    
154            if (displayChildren) {
155                buffer.append(' ');
156                children.appendUsage(buffer, helpSettings, comp);
157            }
158        }
159    
160        /**
161         * @return a description of this parent option
162         */
163        public String getDescription() {
164            return description;
165        }
166    
167        /*
168         * (non-Javadoc)
169         *
170         * @see org.apache.commons.cli2.Option#helpLines(int, java.util.Set,
171         *      java.util.Comparator)
172         */
173        public List helpLines(final int depth,
174                              final Set helpSettings,
175                              final Comparator comp) {
176            final List helpLines = new ArrayList();
177            helpLines.add(new HelpLineImpl(this, depth));
178    
179            if (helpSettings.contains(DisplaySetting.DISPLAY_PARENT_ARGUMENT) && (argument != null)) {
180                helpLines.addAll(argument.helpLines(depth + 1, helpSettings, comp));
181            }
182    
183            if (helpSettings.contains(DisplaySetting.DISPLAY_PARENT_CHILDREN) && (children != null)) {
184                helpLines.addAll(children.helpLines(depth + 1, helpSettings, comp));
185            }
186    
187            return helpLines;
188        }
189    
190        /**
191         * @return Returns the argument.
192         */
193        public Argument getArgument() {
194            return argument;
195        }
196    
197        /**
198         * @return Returns the children.
199         */
200        public Group getChildren() {
201            return children;
202        }
203    
204        /**
205         * Split the token using the specified separator character.
206         * @param arguments the current position in the arguments iterator
207         * @param separator the separator char to split on
208         */
209        private void handleInitialSeparator(final ListIterator arguments,
210                                            final char separator) {
211            // next token
212            final String newArgument = (String) arguments.next();
213    
214            // split the token
215            final int initialIndex = newArgument.indexOf(separator);
216    
217            if (initialIndex > 0) {
218                arguments.remove();
219                arguments.add(newArgument.substring(0, initialIndex));
220                String value = newArgument.substring(initialIndex + 1);
221                // The value obviously isn't an option, so we need to quote it if looks like an option.
222                // The quotes will be removed later
223                if (value.startsWith("-")) {
224                    value = '"' + value + '"';
225                }
226                arguments.add(value);
227                arguments.previous();
228            }
229    
230            arguments.previous();
231        }
232    
233        /*
234         * @see org.apache.commons.cli2.Option#findOption(java.lang.String)
235         */
236        public Option findOption(final String trigger) {
237            final Option found = super.findOption(trigger);
238    
239            if ((found == null) && (children != null)) {
240                return children.findOption(trigger);
241            } else {
242                return found;
243            }
244        }
245    
246        public void defaults(final WriteableCommandLine commandLine) {
247            super.defaults(commandLine);
248    
249            if (argument != null) {
250                argument.defaultValues(commandLine, this);
251            }
252    
253            if (children != null) {
254                children.defaults(commandLine);
255            }
256        }
257    }