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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package com.sun.tools.jextract;
  24 
  25 import jdk.internal.joptsimple.OptionException;
  26 import jdk.internal.joptsimple.OptionParser;
  27 import jdk.internal.joptsimple.OptionSet;
  28 import jdk.internal.joptsimple.util.KeyValuePair;
  29 
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.nio.file.Files;
  33 import java.nio.file.Path;
  34 import java.nio.file.Paths;
  35 import java.text.MessageFormat;
  36 import java.util.logging.ConsoleHandler;
  37 import java.util.logging.Level;
  38 import java.util.logging.Logger;
  39 import java.util.logging.SimpleFormatter;
  40 import java.util.Locale;
  41 import java.util.ResourceBundle;
  42 
  43 public final class Main {
  44     public static final boolean DEBUG = Boolean.getBoolean("jextract.debug");
  45 
  46     // FIXME: Remove this if/when the macros support is deemed stable
  47     public static boolean INCLUDE_MACROS = Boolean.parseBoolean(System.getProperty("jextract.INCLUDE_MACROS", "true"));
  48 
  49     private static final String MESSAGES_RESOURCE = "com.sun.tools.jextract.resources.Messages";
  50 
  51     private static final ResourceBundle MESSAGES_BUNDLE;
  52     static {
  53         MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
  54     }
  55 
  56     public static String format(String msgId, Object... args) {
  57         return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
  58     }
  59 
  60     final Context ctx;
  61     String targetPackage;
  62 
  63     public Main(Context ctx) {
  64         this.ctx = ctx;
  65     }
  66 
  67     private void processPackageMapping(Object arg) {
  68         String str = (String) arg;
  69         Path p = null;
  70         String pkgName;
  71         if (str.indexOf('=') == -1) {
  72             pkgName = str;
  73         } else {
  74             KeyValuePair kv = KeyValuePair.valueOf(str);
  75             p = Paths.get(kv.key);
  76             pkgName = kv.value;
  77 
  78             if (!Files.isDirectory(p)) {
  79                 throw new IllegalArgumentException(format("not.a.directory", kv.key));
  80             }
  81         }
  82 
  83         Validators.validPackageName(pkgName);
  84         ctx.usePackageForFolder(p, pkgName);
  85     }
  86 
  87     private void processHeader(Object header) {
  88         Path p = Paths.get((String) header);
  89         if (!Files.isReadable(p)) {
  90             throw new IllegalArgumentException(format("cannot.read.header.file", header));
  91         }
  92         p = p.toAbsolutePath();
  93         ctx.usePackageForFolder(p.getParent(), targetPackage);
  94         ctx.sources.add(p);
  95     }
  96 
  97     private void setupLogging(Level level) {
  98         Logger logger = ctx.logger;
  99         logger.setUseParentHandlers(false);
 100         ConsoleHandler log = new ConsoleHandler();
 101         System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %5$s%n");
 102         log.setFormatter(new SimpleFormatter());
 103         logger.setLevel(level);
 104         log.setLevel(level);
 105         logger.addHandler(log);
 106     }
 107 
 108     private void printHelp(OptionParser parser) {
 109         try {
 110             parser.printHelpOn(System.err);
 111         } catch (IOException ex) {
 112             if (Main.DEBUG) {
 113                 ex.printStackTrace(System.err);
 114             }
 115         }

 116     }
 117 
 118     public int run(String[] args) {
 119         OptionParser parser = new OptionParser();
 120         parser.accepts("dry-run", format("help.dry_run"));
 121         parser.accepts("I", format("help.I")).withRequiredArg();
 122         // FIXME: -L not yet implemented. This 'jextract time'
 123         // option is expected to specify paths to load shared libraries
 124         // to check & warn missing symbols.
 125         parser.accepts("L", format("help.L")).withRequiredArg();
 126         parser.accepts("l", format("help.l")).withRequiredArg();
 127         parser.accepts("o", format("help.o")).withRequiredArg();
 128         parser.accepts("t", format("help.t")).withRequiredArg();
 129         parser.accepts("m", format("help.m")).withRequiredArg();
 130         parser.accepts("h", format("help.h")).forHelp();
 131         parser.accepts("help", format("help.h")).forHelp();
 132         parser.accepts("C", format("help.C")).withRequiredArg();
 133         parser.accepts("log", format("help.log")).withRequiredArg();
 134         parser.accepts("rpath", format("help.rpath")).withRequiredArg();
 135         parser.accepts("?", format("help.h")).forHelp();
 136         parser.nonOptions(format("help.non.option"));
 137 
 138         OptionSet options = null;
 139         try {
 140              options = parser.parse(args);
 141         } catch (OptionException oe) {
 142              System.err.println(oe.getMessage());
 143              if (Main.DEBUG) {
 144                  oe.printStackTrace(System.err);
 145              }
 146              printHelp(parser);
 147              return 1;
 148         }
 149 
 150         if (args.length == 0 || options.has("h") || options.has("?") || options.has("help")) {
 151              printHelp(parser);
 152              return 1;
 153         }
 154 
 155         if (options.has("log")) {
 156             setupLogging(Level.parse((String) options.valueOf("log")));
 157         } else {
 158             setupLogging(Level.WARNING);
 159         }
 160 
 161         if (options.has("I")) {
 162             options.valuesOf("I").forEach(p -> ctx.clangArgs.add("-I" + p));
 163         }
 164 
 165         if (options.has("C")) {
 166             options.valuesOf("C").forEach(p -> ctx.clangArgs.add((String) p));
 167         }
 168 
 169         if (options.has("l")) {
 170             try {
 171                 options.valuesOf("l").forEach(p -> {
 172                     String lib = (String)p;
 173                     if (lib.indexOf(File.separatorChar) != -1) {
 174                         throw new IllegalArgumentException(format("l.name.should.not.be.path", lib));
 175                     }
 176                     ctx.libraries.add(lib);
 177                 });
 178             } catch (IllegalArgumentException iae) {
 179                 System.err.println(iae.getMessage());
 180                 if (Main.DEBUG) {
 181                     iae.printStackTrace(System.err);
 182                 }
 183                 return 1;
 184             }
 185         }
 186 
 187         if (options.has("rpath")) {
 188             options.valuesOf("rpath").forEach(p -> ctx.libraryPaths.add((String) p));
 189         }
 190 
 191         targetPackage = options.has("t") ? (String) options.valueOf("t") : "";
 192         if (!targetPackage.isEmpty()) {
 193             Validators.validPackageName(targetPackage);
 194         }
 195 
 196         if (options.has("m")) {
 197             options.valuesOf("m").forEach(this::processPackageMapping);
 198         }
 199 
 200         try {
 201             options.nonOptionArguments().stream().forEach(this::processHeader);
 202             ctx.parse(AsmCodeFactory::new);
 203         } catch (RuntimeException re) {
 204             System.err.println(re.getMessage());
 205             if (Main.DEBUG) {
 206                 re.printStackTrace(System.err);
 207             }
 208             return 2;
 209         }
 210 
 211         if (options.has("dry-run")) {
 212             return 0;
 213         }
 214 
 215         String outputName = options.has("o")? (String)options.valueOf("o") :
 216             options.nonOptionArguments().get(0) + ".jar";
 217         Path jar = Paths.get(outputName);
 218         try {
 219             ctx.collectJarFile(jar, targetPackage);
 220         } catch (IOException ex) {
 221             System.err.println(format("cannot.write.jar.file", jar, ex));
 222             if (Main.DEBUG) {
 223                 ex.printStackTrace(System.err);
 224             }
 225             return 3;
 226         }
 227 
 228         return 0;
 229     }
 230 
 231     public static void main(String... args) {
 232         Main instance = new Main(Context.getInstance());
 233 
 234         System.exit(instance.run(args));
 235     }
 236 
 237 }
--- EOF ---