001    /*
002     * Copyright 2006-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.main;
027    
028    import com.sun.tools.javac.util.Log;
029    import com.sun.tools.javac.util.Options;
030    import java.io.PrintWriter;
031    import java.util.Arrays;
032    import java.util.Collection;
033    
034    /**
035     * TODO: describe com.sun.tools.javac.main.JavacOption
036     *
037     * <p><b>This is NOT part of any API supported by Sun Microsystems.
038     * If you write code that depends on this, you do so at your own
039     * risk.  This code and its internal interfaces are subject to change
040     * or deletion without notice.</b></p>
041     */
042    public interface JavacOption {
043    
044        OptionKind getKind();
045    
046        /** Does this option take a (separate) operand?
047         *  @return true if this option takes a separate operand
048         */
049        boolean hasArg();
050    
051        /** Does argument string match option pattern?
052         *  @param arg   the command line argument string
053         *  @return true if {@code arg} matches this option
054         */
055        boolean matches(String arg);
056    
057        /** Process an option with an argument.
058         *  @param options the accumulated set of analyzed options
059         *  @param option  the option to be processed
060         *  @param arg     the arg for the option to be processed
061         *  @return true if an error was detected
062         */
063        boolean process(Options options, String option, String arg);
064    
065        /** Process the option with no argument.
066         *  @param options the accumulated set of analyzed options
067         *  @param option  the option to be processed
068         *  @return true if an error was detected
069         */
070        boolean process(Options options, String option);
071    
072        OptionName getName();
073    
074        enum OptionKind {
075            NORMAL,
076            EXTENDED,
077            HIDDEN,
078        }
079    
080        enum ChoiceKind {
081            ONEOF,
082            ANYOF
083        }
084    
085        /** This class represents an option recognized by the main program
086         */
087        static class Option implements JavacOption {
088    
089            /** Option string.
090             */
091            OptionName name;
092    
093            /** Documentation key for arguments.
094             */
095            String argsNameKey;
096    
097            /** Documentation key for description.
098             */
099            String descrKey;
100    
101            /** Suffix option (-foo=bar or -foo:bar)
102             */
103            boolean hasSuffix;
104    
105            /** The kind of choices for this option, if any.
106             */
107            ChoiceKind choiceKind;
108    
109            /** The choices for this option, if any.
110             */
111            Collection<String> choices;
112    
113            Option(OptionName name, String argsNameKey, String descrKey) {
114                this.name = name;
115                this.argsNameKey = argsNameKey;
116                this.descrKey = descrKey;
117                char lastChar = name.optionName.charAt(name.optionName.length()-1);
118                hasSuffix = lastChar == ':' || lastChar == '=';
119            }
120    
121            Option(OptionName name, String descrKey) {
122                this(name, null, descrKey);
123            }
124    
125            Option(OptionName name, String descrKey, ChoiceKind choiceKind, String... choices) {
126                this(name, descrKey, choiceKind, Arrays.asList(choices));
127            }
128    
129            Option(OptionName name, String descrKey, ChoiceKind choiceKind, Collection<String> choices) {
130                this(name, null, descrKey);
131                if (choiceKind == null || choices == null)
132                    throw new NullPointerException();
133                this.choiceKind = choiceKind;
134                this.choices = choices;
135            }
136    
137            @Override
138            public String toString() {
139                return name.optionName;
140            }
141    
142            public boolean hasArg() {
143                return argsNameKey != null && !hasSuffix;
144            }
145    
146            public boolean matches(String option) {
147                if (!hasSuffix)
148                    return option.equals(name.optionName);
149    
150                if (!option.startsWith(name.optionName))
151                    return false;
152    
153                if (choices != null) {
154                    String arg = option.substring(name.optionName.length());
155                    if (choiceKind == ChoiceKind.ONEOF)
156                        return choices.contains(arg);
157                    else {
158                        for (String a: arg.split(",+")) {
159                            if (!choices.contains(a))
160                                return false;
161                        }
162                    }
163                }
164    
165                return true;
166            }
167    
168            /** Print a line of documentation describing this option, if standard.
169             * @param out the stream to which to write the documentation
170             */
171            void help(PrintWriter out) {
172                String s = "  " + helpSynopsis();
173                out.print(s);
174                for (int j = Math.min(s.length(), 28); j < 29; j++) out.print(" ");
175                Log.printLines(out, Main.getLocalizedString(descrKey));
176            }
177    
178            String helpSynopsis() {
179                StringBuilder sb = new StringBuilder();
180                sb.append(name);
181                if (argsNameKey == null) {
182                    if (choices != null) {
183                        String sep = "{";
184                        for (String c: choices) {
185                            sb.append(sep);
186                            sb.append(c);
187                            sep = ",";
188                        }
189                        sb.append("}");
190                    }
191                } else {
192                    if (!hasSuffix)
193                        sb.append(" ");
194                    sb.append(Main.getLocalizedString(argsNameKey));
195                }
196    
197                return sb.toString();
198            }
199    
200            /** Print a line of documentation describing this option, if non-standard.
201             *  @param out the stream to which to write the documentation
202             */
203            void xhelp(PrintWriter out) {}
204    
205            /** Process the option (with arg). Return true if error detected.
206             */
207            public boolean process(Options options, String option, String arg) {
208                if (options != null) {
209                    if (choices != null) {
210                        if (choiceKind == ChoiceKind.ONEOF) {
211                            // some clients like to see just one of option+choice set
212                            for (String c: choices)
213                                options.remove(option + c);
214                            String opt = option + arg;
215                            options.put(opt, opt);
216                            // some clients like to see option (without trailing ":")
217                            // set to arg
218                            String nm = option.substring(0, option.length() - 1);
219                            options.put(nm, arg);
220                        } else {
221                            // set option+word for each word in arg
222                            for (String a: arg.split(",+")) {
223                                String opt = option + a;
224                                options.put(opt, opt);
225                            }
226                        }
227                    }
228                    options.put(option, arg);
229                }
230                return false;
231            }
232    
233            /** Process the option (without arg). Return true if error detected.
234             */
235            public boolean process(Options options, String option) {
236                if (hasSuffix)
237                    return process(options, name.optionName, option.substring(name.optionName.length()));
238                else
239                    return process(options, option, option);
240            }
241    
242            public OptionKind getKind() { return OptionKind.NORMAL; }
243    
244            public OptionName getName() { return name; }
245        };
246    
247        /** A nonstandard or extended (-X) option
248         */
249        static class XOption extends Option {
250            XOption(OptionName name, String argsNameKey, String descrKey) {
251                super(name, argsNameKey, descrKey);
252            }
253            XOption(OptionName name, String descrKey) {
254                this(name, null, descrKey);
255            }
256            XOption(OptionName name, String descrKey, ChoiceKind kind, String... choices) {
257                super(name, descrKey, kind, choices);
258            }
259            XOption(OptionName name, String descrKey, ChoiceKind kind, Collection<String> choices) {
260                super(name, descrKey, kind, choices);
261            }
262            @Override
263            void help(PrintWriter out) {}
264            @Override
265            void xhelp(PrintWriter out) { super.help(out); }
266            @Override
267            public OptionKind getKind() { return OptionKind.EXTENDED; }
268        };
269    
270        /** A hidden (implementor) option
271         */
272        static class HiddenOption extends Option {
273            HiddenOption(OptionName name) {
274                super(name, null, null);
275            }
276            HiddenOption(OptionName name, String argsNameKey) {
277                super(name, argsNameKey, null);
278            }
279            @Override
280            void help(PrintWriter out) {}
281            @Override
282            void xhelp(PrintWriter out) {}
283            @Override
284            public OptionKind getKind() { return OptionKind.HIDDEN; }
285        };
286    
287    }