GNUStyleOptions.java revision 16237:91d2d3dee7b4
1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.jar;
27
28import java.io.File;
29import java.io.PrintStream;
30import java.io.PrintWriter;
31import java.lang.module.ModuleFinder;
32import java.lang.module.ModuleDescriptor.Version;
33import java.nio.file.Path;
34import java.nio.file.Paths;
35import java.util.regex.Pattern;
36import java.util.regex.PatternSyntaxException;
37
38/**
39 * Parser for GNU Style Options.
40 */
41class GNUStyleOptions {
42
43    static class BadArgs extends Exception {
44        static final long serialVersionUID = 0L;
45
46        boolean showUsage;
47
48        BadArgs(String key, String arg) { super(Main.formatMsg(key, arg)); }
49        BadArgs(String key) { super(Main.getMsg(key)); }
50
51        BadArgs showUsage(boolean b) {
52            showUsage = b;
53            return this;
54        }
55    }
56
57    static Option[] recognizedOptions = {
58            // Main operations
59            new Option(false, OptionType.MAIN_OPERATION, "--create", "-c") {
60                void process(Main tool, String opt, String arg) throws BadArgs {
61                    if (tool.iflag || tool.tflag || tool.uflag || tool.xflag || tool.dflag)
62                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
63                    tool.cflag = true;
64                }
65            },
66            new Option(true, OptionType.MAIN_OPERATION, "--generate-index", "-i") {
67                void process(Main tool, String opt, String arg) throws BadArgs {
68                    if (tool.cflag || tool.tflag || tool.uflag || tool.xflag || tool.dflag)
69                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
70                    tool.iflag = true;
71                    tool.rootjar = arg;
72                }
73            },
74            new Option(false, OptionType.MAIN_OPERATION, "--list", "-t") {
75                void process(Main tool, String opt, String arg) throws BadArgs {
76                    if (tool.cflag || tool.iflag || tool.uflag || tool.xflag || tool.dflag)
77                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
78                    tool.tflag = true;
79                }
80            },
81            new Option(false, OptionType.MAIN_OPERATION, "--update", "-u") {
82                void process(Main tool, String opt, String arg) throws BadArgs {
83                    if (tool.cflag || tool.iflag || tool.tflag || tool.xflag || tool.dflag)
84                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
85                    tool.uflag = true;
86                }
87            },
88            new Option(false, OptionType.MAIN_OPERATION, "--extract", "-x") {
89                void process(Main tool, String opt, String arg) throws BadArgs {
90                    if (tool.cflag || tool.iflag  || tool.tflag || tool.uflag || tool.dflag)
91                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
92                    tool.xflag = true;
93                }
94            },
95            new Option(false, OptionType.MAIN_OPERATION, "--print-module-descriptor", "-d") {
96                void process(Main tool, String opt, String arg) throws BadArgs {
97                    if (tool.cflag || tool.iflag  || tool.tflag || tool.uflag || tool.xflag)
98                        throw new BadArgs("error.multiple.main.operations").showUsage(true);
99                    tool.dflag = true;
100                }
101            },
102
103            // Additional options
104            new Option(true, OptionType.ANY, "--file", "-f") {
105                void process(Main jartool, String opt, String arg) {
106                    jartool.fname = arg;
107                }
108            },
109            new Option(false, OptionType.ANY, "--verbose", "-v") {
110                void process(Main jartool, String opt, String arg) {
111                    jartool.vflag = true;
112                }
113            },
114            new Option(false, OptionType.CREATE, "--normalize", "-n") {
115                void process(Main jartool, String opt, String arg) {
116                    jartool.nflag = true;
117                }
118                boolean isHidden() { return true; }
119            },
120            new Option(true, OptionType.CREATE_UPDATE, "--main-class", "-e") {
121                void process(Main jartool, String opt, String arg) {
122                    jartool.ename = arg;
123                }
124            },
125            new Option(true, OptionType.CREATE_UPDATE, "--manifest", "-m") {
126                void process(Main jartool, String opt, String arg) {
127                    jartool.mname = arg;
128                }
129            },
130            new Option(false, OptionType.CREATE_UPDATE, "--no-manifest", "-M") {
131                void process(Main jartool, String opt, String arg) {
132                    jartool.Mflag = true;
133                }
134            },
135            new Option(true, OptionType.CREATE_UPDATE, "--module-version") {
136                void process(Main jartool, String opt, String arg) {
137                    jartool.moduleVersion = Version.parse(arg);
138                }
139            },
140            new Option(true, OptionType.CREATE_UPDATE, "--hash-modules") {
141                void process(Main jartool, String opt, String arg) throws BadArgs {
142                    try {
143                        jartool.modulesToHash = Pattern.compile(arg);
144                    } catch (PatternSyntaxException e) {
145                        throw new BadArgs("err.badpattern", arg).showUsage(true);
146                    }
147                }
148            },
149            new Option(true, OptionType.CREATE_UPDATE, "--module-path", "-p") {
150                void process(Main jartool, String opt, String arg) {
151                    String[] dirs = arg.split(File.pathSeparator);
152                    Path[] paths = new Path[dirs.length];
153                    int i = 0;
154                    for (String dir : dirs) {
155                        paths[i++] = Paths.get(dir);
156                    }
157                    jartool.moduleFinder = ModuleFinder.compose(jartool.moduleFinder,
158                                                                ModuleFinder.of(paths));
159                }
160            },
161            new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
162                void process(Main jartool, String opt, String arg) {
163                    jartool.flag0 = true;
164                }
165            },
166
167            // Hidden options
168            new Option(false, OptionType.OTHER, "-P") {
169                void process(Main jartool, String opt, String arg) {
170                    jartool.pflag = true;
171                }
172                boolean isHidden() { return true; }
173            },
174
175            // Other options
176            new Option(true, true, OptionType.OTHER, "--help", "-h") {
177                void process(Main jartool, String opt, String arg) throws BadArgs {
178                    if (jartool.info == null) {
179                        if (arg == null) {
180                            jartool.info = Main.Info.HELP;
181                            return;
182                        }
183
184                        if (!arg.equals("compat"))
185                            throw new BadArgs("error.illegal.option", arg).showUsage(true);
186
187                        jartool.info = Main.Info.COMPAT_HELP;
188                    }
189                }
190            },
191            new Option(false, OptionType.OTHER, "--version") {
192                void process(Main jartool, String opt, String arg) {
193                    if (jartool.info == null)
194                        jartool.info = Main.Info.VERSION;
195                }
196            }
197    };
198
199    enum OptionType {
200        MAIN_OPERATION("main"),
201        ANY("any"),
202        CREATE("create"),
203        CREATE_UPDATE("create.update"),
204        CREATE_UPDATE_INDEX("create.update.index"),
205        OTHER("other");
206
207        /** Resource lookup section prefix. */
208        final String name;
209
210        OptionType(String name) { this.name = name; }
211    }
212
213    static abstract class Option {
214        final boolean hasArg;
215        final boolean argIsOptional;
216        final String[] aliases;
217        final OptionType type;
218
219        Option(boolean hasArg, OptionType type, String... aliases) {
220            this(hasArg, false, type, aliases);
221        }
222
223        Option(boolean hasArg, boolean argIsOptional, OptionType type, String... aliases) {
224            this.hasArg = hasArg;
225            this.argIsOptional = argIsOptional;
226            this.type = type;
227            this.aliases = aliases;
228        }
229
230        boolean isHidden() { return false; }
231
232        boolean matches(String opt) {
233            for (String a : aliases) {
234                if (a.equals(opt)) {
235                    return true;
236                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
237                    return true;
238                } else if (opt.startsWith("--help") && opt.startsWith(a + ":")) {
239                    return true;
240                }
241            }
242            return false;
243        }
244
245        abstract void process(Main jartool, String opt, String arg) throws BadArgs;
246    }
247
248    static int parseOptions(Main jartool, String[] args) throws BadArgs {
249        int count = 0;
250        if (args.length == 0) {
251            jartool.info = Main.Info.USAGE_TRYHELP;
252            return 0;
253        }
254
255        // process options
256        for (; count < args.length; count++) {
257            if (args[count].charAt(0) != '-' || args[count].equals("-C")
258                || args[count].equals("--release"))
259                break;
260
261            String name = args[count];
262            Option option = getOption(name);
263            String param = null;
264            if (option.hasArg) {
265                if (name.startsWith("--help")) {  // "special" optional separator
266                    if (name.indexOf(':') > 0) {
267                        param = name.substring(name.indexOf(':') + 1, name.length());
268                    }
269                } else if (name.startsWith("--") && name.indexOf('=') > 0) {
270                    param = name.substring(name.indexOf('=') + 1, name.length());
271                } else if (count + 1 < args.length) {
272                    param = args[++count];
273                }
274                if (!option.argIsOptional &&
275                    (param == null || param.isEmpty() || param.charAt(0) == '-')) {
276                    throw new BadArgs("error.missing.arg", name).showUsage(true);
277                }
278            }
279            option.process(jartool, name, param);
280        }
281
282        return count;
283    }
284
285    private static Option getOption(String name) throws BadArgs {
286        for (Option o : recognizedOptions) {
287            if (o.matches(name)) {
288                return o;
289            }
290        }
291        throw new BadArgs("error.unrecognized.option", name).showUsage(true);
292    }
293
294    static void printHelp(PrintWriter out) {
295        out.format("%s%n", Main.getMsg("main.help.preopt"));
296        for (OptionType type : OptionType.values()) {
297            boolean typeHeadingWritten = false;
298
299            for (Option o : recognizedOptions) {
300                if (!o.type.equals(type))
301                    continue;
302                String name = o.aliases[0].substring(1); // there must always be at least one name
303                name = name.charAt(0) == '-' ? name.substring(1) : name;
304                if (o.isHidden() || name.equals("h")) {
305                    continue;
306                }
307                if (!typeHeadingWritten) {
308                    out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
309                    typeHeadingWritten = true;
310                }
311                out.format("%s%n", Main.getMsg("main.help.opt." + type.name + "." + name));
312            }
313        }
314        out.format("%n%s%n%n", Main.getMsg("main.help.postopt"));
315    }
316
317    static void printCompatHelp(PrintWriter out) {
318        out.format("%s%n", Main.getMsg("usage.compat"));
319    }
320
321    static void printUsageTryHelp(PrintWriter out) {
322        out.format("%s%n", Main.getMsg("main.usage.summary.try"));
323    }
324
325    static void printVersion(PrintWriter out) {
326        out.format("%s %s%n", "jar", System.getProperty("java.version"));
327    }
328}
329