com.github.rvesse.airline.parser.options.ClassicGetOptParser.java Source code

Java tutorial

Introduction

Here is the source code for com.github.rvesse.airline.parser.options.ClassicGetOptParser.java

Source

/**
 * Copyright (C) 2010-16 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.rvesse.airline.parser.options;

import java.util.List;

import org.apache.commons.collections4.iterators.PeekingIterator;

import com.github.rvesse.airline.Context;
import com.github.rvesse.airline.model.OptionMetadata;
import com.github.rvesse.airline.parser.ParseState;
import com.github.rvesse.airline.parser.errors.ParseOptionUnexpectedException;

/**
 * An options parsing that parses options given in classic get-opt style where
 * multiple options may be concatenated together
 * <p>
 * For example {@code -abc} could potentially set the option {@code -a},
 * {@code -b} and {@code -c} however interpretation is contextual depending on
 * the option configuration. Say option {@code -a} has arity of 1 then the
 * remainder of the token (the {@code bc}) would be interpreted as being the
 * value passed to the {@code -a} option.
 * </p>
 *
 * @param <T>
 */
public class ClassicGetOptParser<T> extends AbstractOptionParser<T> {
    public ParseState<T> parseOptions(PeekingIterator<String> tokens, ParseState<T> state,
            List<OptionMetadata> allowedOptions) {
        if (!hasShortNamePrefix(tokens.peek())) {
            return null;
        }

        // remove leading dash from token
        String remainingToken = tokens.peek().substring(1);

        ParseState<T> nextState = state;
        boolean first = true;
        while (!remainingToken.isEmpty()) {
            char tokenCharacter = remainingToken.charAt(0);

            // is the current token character a single letter option?
            OptionMetadata option = findOption(state, allowedOptions, "-" + tokenCharacter);
            if (option == null) {
                return null;
            }

            nextState = nextState.pushContext(Context.OPTION).withOption(option);

            // remove current token character
            remainingToken = remainingToken.substring(1);

            // for no argument options, process the option and remove the
            // character from the token
            if (option.getArity() == 0) {
                nextState = nextState.withOptionValue(option, Boolean.TRUE.toString()).popContext();
                first = false;
                continue;
            }

            if (option.getArity() == 1) {
                // we must, consume the current token so we can see the next
                // token
                tokens.next();

                // if current token has more characters, this is the value;
                // otherwise it is the next token
                if (!remainingToken.isEmpty()) {
                    nextState = nextState.withOptionValue(option, remainingToken).popContext();
                } else if (tokens.hasNext()) {
                    nextState = nextState.withOptionValue(option, tokens.next()).popContext();
                }

                return nextState;
            }

            // Don't throw an error if this is the first option we have seen as
            // in that case the option may legitimately be processed by another
            // option parser
            if (first)
                return null;
            throw new ParseOptionUnexpectedException("Short options style can not be used with option %s", option);
        }

        // consume the current token
        tokens.next();

        return nextState;
    }
}