hello Tom + all,

the attached proposed patch adds support for the above options in an attempt 
to make gjavah compatible (options-wise) with the RI.

not knowing or having used CNI before i have not tested it with that option.  
the JNI side on the other hand seems to work.

ok to commit?


cheers;
rsn
Index: CniIncludePrinter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/CniIncludePrinter.java,v
retrieving revision 1.1
diff -u -r1.1 CniIncludePrinter.java
--- CniIncludePrinter.java	28 Jul 2006 15:22:29 -0000	1.1
+++ CniIncludePrinter.java	26 Sep 2006 10:31:41 -0000
@@ -47,21 +47,34 @@
     extends Printer
 {

-  protected CniIncludePrinter(Main classpath)
+  protected CniIncludePrinter(Main classpath, File outFile, boolean isDir,
+                              boolean force)
   {
-    super(classpath);
+    super(classpath, outFile, isDir, force);
   }

-  public void printClass(File outputDir, ClassWrapper klass) throws IOException
+  protected void writePreambleImpl(PrintStream ps)
+  {
+    // does nothing
+  }
+
+  protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+                                           ClassWrapper klass)
+  {
+    return new PrintStream(fos);
+  }
+
+  public void printClass(ClassWrapper klass) throws IOException
   {
     // Never write Object or Class. This is a hack, maybe
     // the user would like to see what they look like...
     if (klass.name.equals("java/lang/Object")
         || klass.name.equals("java/lang/Class"))
       return;
-    File klassFile = new File(outputDir, klass.name + ".h");
-    klassFile.getParentFile().mkdirs();
-    PrintStream ps = new PrintStream(new FileOutputStream(klassFile));
+    PrintStream ps = getPrintStream(klass.name + ".h", klass);
+    if (ps == null)
+      return;
+    ps.println();
     klass.printFully(ps);
     ps.close();
   }
Index: CniStubPrinter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java,v
retrieving revision 1.1
diff -u -r1.1 CniStubPrinter.java
--- CniStubPrinter.java	28 Jul 2006 15:22:29 -0000	1.1
+++ CniStubPrinter.java	26 Sep 2006 10:33:00 -0000
@@ -41,6 +41,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.Iterator;

@@ -51,9 +52,10 @@
     extends Printer
 {

-  protected CniStubPrinter(Main classpath)
+  protected CniStubPrinter(Main classpath, File outFile, boolean isDir,
+                           boolean force)
   {
-    super(classpath);
+    super(classpath, outFile, isDir, force);
   }

   private void printDecl(CniPrintStream out, String className, MethodNode method)
@@ -72,24 +74,34 @@
     out.print(")");
   }

-  public void printClass(File outputDir, ClassWrapper klass) throws IOException
+  protected void writePreambleImpl(PrintStream out)
   {
-    if (! klass.hasNativeMethod())
-      return;
-    File klassFile = new File(outputDir, klass.name + ".cc");
-    klassFile.getParentFile().mkdirs();
-    String className = klass.name.replaceAll("/", "::");
-
-    CniPrintStream out = new CniPrintStream(new FileOutputStream(klassFile));
     out.println("// This file is intended to give you a head start on implementing native");
     out.println("// methods using CNI.");
     out.println("// Be aware: running 'gcjh -stubs' once more for this class may");
     out.println("// overwrite any edits you have made to this file.");
     out.println();
-
-    out.println("#include <" + klass.name + ".h>");
     out.println("#include <gcj/cni.h>");
     out.println("#include <java/lang/UnsupportedOperationException.h>");
+  }
+
+  protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+                                           ClassWrapper klass)
+  {
+    return new CniPrintStream(fos);
+  }
+
+  public void printClass(ClassWrapper klass) throws IOException
+  {
+    if (! klass.hasNativeMethod())
+      return;
+    String className = klass.name.replaceAll("/", "::");
+    CniPrintStream out = (CniPrintStream) getPrintStream(klass.name + ".cc",
+                                                         klass);
+    if (out == null)
+      return;
+    out.println();
+    out.println("#include <" + klass.name + ".h>");
     out.println();

     Iterator i = klass.methods.iterator();
Index: JniIncludePrinter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/JniIncludePrinter.java,v
retrieving revision 1.2
diff -u -r1.2 JniIncludePrinter.java
--- JniIncludePrinter.java	9 Aug 2006 17:18:31 -0000	1.2
+++ JniIncludePrinter.java	26 Sep 2006 10:33:55 -0000
@@ -41,6 +41,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.Iterator;

@@ -52,9 +53,10 @@
     extends Printer
 {

-  protected JniIncludePrinter(Main classpath)
+  protected JniIncludePrinter(Main classpath, File outFile, boolean isDir,
+                              boolean force)
   {
-    super(classpath);
+    super(classpath, outFile, isDir, force);
   }

   private void writeFields(ClassWrapper klass, JniPrintStream out)
@@ -93,17 +95,27 @@
       out.println();
   }

-  public void printClass(File outputDir, ClassWrapper klass) throws IOException
+  protected void writePreambleImpl(PrintStream out)
+  {
+    out.println("/* DO NOT EDIT THIS FILE - it is machine generated */");
+    out.println();
+    out.println("#include <jni.h>");
+  }
+
+  protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+                                           ClassWrapper klass)
+  {
+    return new JniPrintStream(classpath, fos, klass);
+  }
+
+  public void printClass(ClassWrapper klass) throws IOException
   {
     if (! klass.hasNativeMethod())
       return;
     String xname = JniHelper.mangle(klass.name);
-    File outFile = new File(outputDir, xname + ".h");
-
-    JniPrintStream out = new JniPrintStream(classpath,
-                                            new FileOutputStream(outFile),
-                                            klass);
-    out.println("/* DO NOT EDIT THIS FILE - it is machine generated */");
+    JniPrintStream out = (JniPrintStream) getPrintStream(xname + ".h", klass);
+    if (out == null)
+      return;
     out.println();
     out.print("#ifndef __");
     out.print(xname);
@@ -112,8 +124,6 @@
     out.print(xname);
     out.println("__");
     out.println();
-    out.println("#include <jni.h>");
-    out.println();
     out.println("#ifdef __cplusplus");
     out.println("extern \"C\"");
     out.println("{");
@@ -144,7 +154,6 @@
     out.print("#endif /* __");
     out.print(xname);
     out.println("__ */");
-
     out.close();
   }

Index: JniStubPrinter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/JniStubPrinter.java,v
retrieving revision 1.1
diff -u -r1.1 JniStubPrinter.java
--- JniStubPrinter.java	28 Jul 2006 15:22:29 -0000	1.1
+++ JniStubPrinter.java	26 Sep 2006 10:34:51 -0000
@@ -41,6 +41,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.Iterator;

@@ -51,25 +52,34 @@
     extends Printer
 {

-  protected JniStubPrinter(Main classpath)
+  protected JniStubPrinter(Main classpath, File outFile, boolean isDir,
+                           boolean force)
   {
-    super(classpath);
+    super(classpath, outFile, isDir, force);
   }

-  public void printClass(File outputDir, ClassWrapper klass) throws IOException
+  protected void writePreambleImpl(PrintStream out)
+  {
+    out.println("/* This file is intended to give you a head start on implementing native");
+    out.println("   methods using JNI.");
+    out.println("   Be aware: running gcjh or compatible tool with '-stubs' option once more");
+    out.println("   for the same input may overwrite any edits you have made to this file.  */");
+  }
+
+  protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+                                           ClassWrapper klass)
+  {
+    return new JniPrintStream(classpath, fos, klass);
+  }
+
+  public void printClass(ClassWrapper klass) throws IOException
   {
     if (! klass.hasNativeMethod())
       return;
     String xname = JniHelper.mangle(klass.name);
-    File outFile = new File(outputDir, xname + ".c");
-
-    JniPrintStream out = new JniPrintStream(classpath,
-                                            new FileOutputStream(outFile),
-                                            klass);
-    out.println("/* This file is intended to give you a head start on implementing native");
-    out.println("   methods using CNI.");
-    out.println("   Be aware: running 'gcjh -stubs' once more for this class may");
-    out.println("   overwrite any edits you have made to this file.  */");
+    JniPrintStream out = (JniPrintStream) getPrintStream(xname + ".c", klass);
+    if (out == null)
+      return;
     out.println();
     out.print("#include <");
     out.print(xname);
@@ -94,5 +104,4 @@
       }
     out.close();
   }
-
 }
Index: Main.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/Main.java,v
retrieving revision 1.3
diff -u -r1.3 Main.java
--- Main.java	22 Sep 2006 01:01:26 -0000	1.3
+++ Main.java	26 Sep 2006 10:35:47 -0000
@@ -70,6 +70,9 @@
   // The output directory.
   String outputDir;

+  // The output file name used if/when -o option is used.
+  String outFileName;
+
   // The loader that we use to load class files.
   URLClassLoader loader;

@@ -85,6 +88,9 @@
   // True if we're emitting CNI code.
   boolean cni;

+  // True if output files should always be written.
+  boolean force;
+
   // Map class names to class wrappers.
   HashMap classMap = new HashMap();

@@ -184,9 +190,24 @@
       {
         if (outputDir != null)
           throw new OptionException("-d already seen");
+        if (outFileName != null)
+          throw new OptionException("only one of -d or -o may be used");
         outputDir = dir;
       }
     });
+    result.add(new Option('o',
+                          "Set output file (only one of -d or -o may be used)",
+                          "FILE")
+    {
+      public void parsed(String fileName) throws OptionException
+      {
+        if (outFileName != null)
+          throw new OptionException("-o already seen");
+        if (outputDir != null)
+          throw new OptionException("only one of -d or -o may be used");
+        outFileName = fileName;
+      }
+    });
     result.add(new Option("cmdfile", "Read command file", "FILE")
     {
       public void parsed(String file) throws OptionException
@@ -212,6 +233,15 @@
         stubs = true;
       }
     });
+    result.add(new Option("jni", "Emit JNI stubs or header (default)")
+    {
+      public void parsed(String arg0) throws OptionException
+      {
+        if (cni)
+          throw new OptionException("only one of -jni or -cni may be used");
+        cni = false;
+      }
+    });
     result.add(new Option("cni", "Emit CNI stubs or header (default JNI)")
     {
       public void parsed(String arg0) throws OptionException
@@ -226,6 +256,13 @@
         verbose = true;
       }
     });
+    result.add(new Option("force", "Output files should always be written")
+    {
+      public void parsed(String arg0) throws OptionException
+      {
+        force = true;
+      }
+    });
     return result;
   }

@@ -242,8 +279,36 @@
     return outputFile;
   }

-  private void writeHeaders(ArrayList klasses, Printer printer,
-                            File outputDirFile) throws IOException
+  /**
+   * @return The [EMAIL PROTECTED] File} object where the generated code will be written.
+   *         Returns <code>null</code> if the option <code>-force</code> was
+   *         specified on the command line and the designated file already
+   *         exists.
+   * @throws IOException if <code>outFileName</code> is not a writable file.
+   */
+  private File makeOutputFile() throws IOException
+  {
+    File result = new File(outFileName);
+    if (result.exists())
+      {
+        if (! result.isFile())
+          throw new IOException("'" + outFileName + "' is not a file");
+        if (! force)
+          {
+            if (verbose)
+              System.err.println("["+ outFileName
+                                 + " already exists.  Use -force to overwrite]");
+            return null;
+          }
+        if (! result.delete())
+          throw new IOException("Was unable to delete existing file: "
+                                + outFileName);
+      }
+    return result;
+  }
+
+  private void writeHeaders(ArrayList klasses, Printer printer)
+      throws IOException
   {
     Iterator i = klasses.iterator();
     while (i.hasNext())
@@ -251,7 +316,7 @@
         ClassWrapper klass = (ClassWrapper) i.next();
         if (verbose)
           System.err.println("[writing " + klass + "]");
-        printer.printClass(outputDirFile, klass);
+        printer.printClass(klass);
       }
   }

@@ -261,21 +326,25 @@
     String[] classNames = p.parse(args);
     loader = classpath.getLoader();

-    File outputFile = makeOutputDirectory();
+    boolean isDirectory = outFileName == null;
+    File outputFile = isDirectory ? makeOutputDirectory() : makeOutputFile();
+    if (outputFile == null)
+      return;
+
     Printer printer;
     if (! cni)
       {
         if (stubs)
-          printer = new JniStubPrinter(this);
+          printer = new JniStubPrinter(this, outputFile, isDirectory, force);
         else
-          printer = new JniIncludePrinter(this);
+          printer = new JniIncludePrinter(this, outputFile, isDirectory, force);
       }
     else
       {
         if (stubs)
-          printer = new CniStubPrinter(this);
+          printer = new CniStubPrinter(this, outputFile, isDirectory, force);
         else
-          printer = new CniIncludePrinter(this);
+          printer = new CniIncludePrinter(this, outputFile, isDirectory, force);
       }

     // First we load all of the files. That way if
@@ -324,7 +393,7 @@
         results.add(klass);
       }

-    writeHeaders(results, printer, outputFile);
+    writeHeaders(results, printer);
   }

   public ArrayList getClassTextList(String name)
Index: Printer.java
===================================================================
RCS file: /cvsroot/classpath/classpath/tools/gnu/classpath/tools/javah/Printer.java,v
retrieving revision 1.1
diff -u -r1.1 Printer.java
--- Printer.java	28 Jul 2006 15:22:29 -0000	1.1
+++ Printer.java	26 Sep 2006 10:37:25 -0000
@@ -39,17 +39,95 @@
 package gnu.classpath.tools.javah;

 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintStream;

 public abstract class Printer
 {
   protected Main classpath;
+  /**
+   * The [EMAIL PROTECTED] File} object that denotes either a directory (when the
+   * <code>-d</code> option was used), or a file (when the <code>-o</code>
+   * option was used) on the command line.
+   */
+  protected File outputFileObject;
+  /**
+   * Set to <code>true</code> if the field <code>outputFileObject</code> denotes
+   * a directory; i.e. for each input class file, one JNI header file will be
+   * generated in that directory.
+   * <p>
+   * Set to <code>false</code> if the field <code>outputFileObject</code>
+   * denotes a file; i.e. all generated headers will be written to that file.
+   */
+  protected boolean isDirectory;
+  /**
+   * Set to <code>true</code> if the output file(s) should always be written.
+   * <p>
+   * When set to <code>false</code>, the contents of the header/stub are only
+   * written to the file if it does not already exist.
+   */
+  protected boolean force;
+  /**
+   * Set to <code>true</code> if all output is directed to one file, and the
+   * common preamble text has already been generated.
+   */
+  protected boolean wrotePreamble;

-  protected Printer(Main classpath)
+  protected Printer(Main classpath, File outFile, boolean isDir, boolean force)
   {
     this.classpath = classpath;
+    if (outFile == null)
+      throw new IllegalArgumentException("File argument MUST NOT be null");
+    outputFileObject = outFile;
+    isDirectory = isDir;
+    if (isDirectory)
+      outputFileObject.mkdirs();
+    else
+      {
+        File parent = outputFileObject.getParentFile();
+        if (parent != null)
+          parent.mkdirs();
+      }
+    this.force = force;
   }

-  public abstract void printClass(File outputDir, ClassWrapper klass)
-      throws IOException;
+  public abstract void printClass(ClassWrapper klass) throws IOException;
+
+  protected abstract void writePreambleImpl(PrintStream ps);
+
+  protected abstract PrintStream getPrintStreamImpl(FileOutputStream fos,
+                                                    ClassWrapper klass);
+
+  protected PrintStream getPrintStream(String fullName, ClassWrapper klass)
+      throws FileNotFoundException
+  {
+    PrintStream result;
+    FileOutputStream fos;
+    if (isDirectory)
+      {
+        File outFile = new File(outputFileObject, fullName);
+        if (outFile.exists() && ! force)
+          return null;
+        fos = new FileOutputStream(outFile);
+        result = getPrintStreamImpl(fos, klass);
+        writePreamble(result);
+      }
+    else
+      {
+        // the first time we open this file, wrotePreamble is false
+        fos = new FileOutputStream(outputFileObject, wrotePreamble);
+        result = getPrintStreamImpl(fos, klass);
+        if (! wrotePreamble)
+          writePreamble(result);
+      }
+    return result;
+  }
+
+  protected void writePreamble(PrintStream out)
+  {
+    writePreambleImpl(out);
+    wrotePreamble = true;
+  }
 }

Attachment: pgpyZQyDtQm96.pgp
Description: PGP signature

Reply via email to