Package org.jnode.shell.syntax

Source Code of org.jnode.shell.syntax.OptionSetSyntax

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell.syntax;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;

import org.jnode.nanoxml.XMLElement;
import org.jnode.shell.CommandLine.Token;


/**
* An OptionSet syntax is like a Powerset syntax, except that:
* <ol>
* <li>the child syntaxes must all be OptionSyntaxes, and
* <li>the syntax supports combining of flag options; e.g. "-ab" means "-a -b"
* </ol>
*
* @author crawley@jnode.org
*/
public class OptionSetSyntax extends GroupSyntax {
   
    private static class FlagSetArgument extends Argument<Boolean> {
       
        private final List<OptionSyntax> flagOptions;
        private final ArgumentBundle bundle;
       
        FlagSetArgument(String label, ArgumentBundle bundle, List<OptionSyntax> flagOptions) {
            super(label, OPTIONAL + MULTIPLE, new Boolean[0], null);
            this.flagOptions = flagOptions;
            this.bundle = bundle;
        }

        @Override
        protected Boolean doAccept(Token token, int argumentFlags) throws CommandSyntaxException {
            String value = token.text;
            int len = value.length();
            if (len < 2 || value.charAt(0) != '-') {
                throw new CommandSyntaxException("not a flag set");
            }
            for (int i = 1; i < len; i++) {
                char ch = value.charAt(i);
                String shortOptName = "-" + ch;
                boolean found = false;
                for (OptionSyntax flagOption : flagOptions) {
                    if (shortOptName.equals(flagOption.getShortOptName())) {
                        bundle.getArgument(flagOption).accept(new Token(shortOptName), 0);
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    throw new CommandSyntaxException("'" + ch + "' is not a known flag");
                }
            }
            return Boolean.TRUE;
        }

        @Override
        protected String argumentKind() {
            return "flags";
        }
    }
   
    private static Comparator<OptionSyntax> SHORT_NAME_ORDER =
        new Comparator<OptionSyntax>() {

            public int compare(OptionSyntax o1, OptionSyntax o2) {
                char c1 = o1.getShortOptName().charAt(1);
                char c2 = o2.getShortOptName().charAt(1);
                boolean l1 = Character.isLowerCase(c1);
                boolean l2 = Character.isLowerCase(c2);
                if (l1 == l2) {
                    return (int) c2 - (int) c1;
                } else {
                    return l1 ? -1 : +1;
                }
            }
        };
   
    private final OptionSyntax[] optionSyntaxes;
   
    public OptionSetSyntax(String label, String description, OptionSyntax... syntaxes) {
        super(label, description, syntaxes);
        this.optionSyntaxes = syntaxes;
    }

    public OptionSetSyntax(String label, OptionSyntax... syntaxes) {
        this(label, null, syntaxes);
    }

    public OptionSetSyntax(OptionSyntax... syntaxes) {
        this(null, null, syntaxes);
    }

    @Override
    public MuSyntax prepare(ArgumentBundle bundle) {
        ArrayList<OptionSyntax> flagOptions = new ArrayList<OptionSyntax>();
        MuSyntax[] childMuSyntaxes = new MuSyntax[optionSyntaxes.length];
        for (int i = 0; i < optionSyntaxes.length; i++) {
            OptionSyntax childSyntax = optionSyntaxes[i];
            Argument<?> arg = bundle.getArgument(childSyntax);
            if (arg instanceof FlagArgument && childSyntax.getShortOptName() != null) {
                flagOptions.add(childSyntax);
            }
            childMuSyntaxes[i] = childSyntax.prepare(bundle);
        }
        if (flagOptions.size() > 1) {
            // We deal with combined flag options by adding a proxy argument to the
            // bundle whose 'accept' method will unpick (say) '-ab', and dispatch
            // it to the corresponding FlagArguments.
            String label = MuSyntax.genLabel();
            FlagSetArgument arg = new FlagSetArgument(label, bundle, flagOptions);
            bundle.addArgument(arg);
            childMuSyntaxes =
                new MuSyntax[] {new MuAlternation(childMuSyntaxes), new MuArgument(label)};
        }
        String label = this.label == null ? MuSyntax.genLabel() : this.label;
        MuSyntax res = new MuAlternation(label,
                new MuSequence(new MuAlternation((String) null, childMuSyntaxes),
                        new MuBackReference(label)),
                null);
        res.resolveBackReferences();
        return res;
    }

    @Override
    public String format(ArgumentBundle bundle) {
        TreeSet<OptionSyntax> shortFlagOpts = new TreeSet<OptionSyntax>(SHORT_NAME_ORDER);
        for (int i = 0; i < optionSyntaxes.length; i++) {
            OptionSyntax optionSyntax = optionSyntaxes[i];
            Argument<?> arg = bundle.getArgument(optionSyntax);
            if (arg instanceof FlagArgument &&
                    optionSyntax.getShortOptName() != null &&
                    optionSyntax.getLongOptName() == null) {
                shortFlagOpts.add(optionSyntax);
            }
        }
        StringBuilder sb = new StringBuilder();
        if (!shortFlagOpts.isEmpty()) {
            sb.append("[ -");
            for (OptionSyntax optionSyntax : shortFlagOpts) {
                sb.append(optionSyntax.getShortOptName().charAt(1));
            }
            sb.append(" ]");
        }
        for (int i = 0; i < optionSyntaxes.length; i++) {
            OptionSyntax optionSyntax = optionSyntaxes[i];
            if (optionSyntax.getShortOptName() == null || !shortFlagOpts.contains(optionSyntax)) {
                if (sb.length() > 0) {
                    sb.append(' ');
                }
                sb.append(optionSyntax.format(bundle));
            }
        }
        return sb.toString();
    }

    @Override
    public XMLElement toXML() {
        return basicElement("optionSet");
    }
}
TOP

Related Classes of org.jnode.shell.syntax.OptionSetSyntax

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.