From 6221b5380137915ae3f2cb9d57c18a556484bd82 Mon Sep 17 00:00:00 2001
From: Kenneth Russel <kbrussel@alum.mit.edu>
Date: Mon, 15 Jun 2009 22:42:48 +0000
Subject: Copied JOGL_2_SANDBOX r145 on to trunk; JOGL_2_SANDBOX branch is now
 closed

git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/gluegen/trunk@147 a78bb65f-1512-4460-ba86-f6dc96a7bf27
---
 src/java/com/sun/gluegen/ant/StaticGLGenTask.java  | 304 +++++++++++++
 .../gluegen/nativesig/NativeSignatureEmitter.java  | 188 ++++++++
 .../NativeSignatureJavaMethodBindingEmitter.java   | 486 +++++++++++++++++++++
 3 files changed, 978 insertions(+)
 create mode 100644 src/java/com/sun/gluegen/ant/StaticGLGenTask.java
 create mode 100755 src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java
 create mode 100755 src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java

(limited to 'src/java/com')

diff --git a/src/java/com/sun/gluegen/ant/StaticGLGenTask.java b/src/java/com/sun/gluegen/ant/StaticGLGenTask.java
new file mode 100644
index 000000000..87619422c
--- /dev/null
+++ b/src/java/com/sun/gluegen/ant/StaticGLGenTask.java
@@ -0,0 +1,304 @@
+package com.sun.gluegen.ant;
+
+/*
+ * StaticGLGenTask.java
+ * Copyright (C) 2003 Rob Grzywinski (rgrzywinski@realityinteractive.com)
+ *
+ * Copying, distribution and use of this software in source and binary
+ * forms, with or without modification, is permitted provided that the
+ * following conditions are met:
+ *
+ * Distributions of source code must reproduce the copyright notice,
+ * this list of conditions and the following disclaimer in the source
+ * code header files; and Distributions of binary code must reproduce
+ * the copyright notice, this list of conditions and the following
+ * disclaimer in the documentation, Read me file, license file and/or
+ * other materials provided with the software distribution.
+ *
+ * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright
+ * holder may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF ANY
+ * KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, NON-INTERFERENCE, ACCURACY OF
+ * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE
+ * COPYRIGHT HOLDER, SUN AND SUN'S LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL THE
+ * COPYRIGHT HOLDER, SUN OR SUN'S LICENSORS BE LIABLE FOR ANY LOST
+ * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT
+ * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION,
+ * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT
+ * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED
+ * WARRANTY OF FITNESS FOR SUCH USES.
+ */
+
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * <p>An <a href="http://ant.apache.org">ANT</a> {@link org.apache.tools.ant.Task}
+ * for using {@link com.sun.gluegen.opengl.BuildStaticGLInfo}.</p>
+ * 
+ * <p>Usage:</p>
+ * <pre>
+    &lt;staticglgen package="[generated files package]" 
+                    headers="[file pattern of GL headers]"
+                    outputdir="[directory to output the generated files]" /&gt;
+ * </pre> 
+ *
+ * @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@yahoo.com</a>
+ */
+// FIXME:  blow out javadoc
+public class StaticGLGenTask extends Task
+{
+    /**
+     * <p>The {@link com.sun.gluegen.opengl.BuildStaticGLInfo} classname.</p>
+     */
+    private static final String GL_GEN = "com.sun.gluegen.opengl.BuildStaticGLInfo";
+    
+    // =========================================================================
+    /**
+     * <p>The {@link org.apache.tools.ant.types.CommandlineJava} that is used
+     * to execute {@link com.sun.gluegen.opengl.BuildStaticGLInfo}.</p>
+     */
+    private CommandlineJava glgenCommandline;
+
+    // =========================================================================
+    /**
+     * <p>The package name for the generated files.</p>
+     */
+    private String packageName;
+
+    /**
+     * <p>The output directory.</p>
+     */
+    private String outputDirectory;
+    
+    /**
+     * <p>The {@link org.apache.tools.ant.types.FileSet} of GL headers.</p>
+     */
+    private FileSet headerSet = new FileSet();
+    
+    // =========================================================================
+    /**
+     * <p>Create and add the VM and classname to {@link org.apache.tools.ant.types.CommandlineJava}.</p>
+     */
+    public StaticGLGenTask()
+    {
+        // create the CommandlineJava that will be used to call BuildStaticGLInfo
+        glgenCommandline = new CommandlineJava();
+        
+        // set the VM and classname in the commandline
+        glgenCommandline.setVm(JavaEnvUtils.getJreExecutable("java"));
+        glgenCommandline.setClassname(GL_GEN);
+    }
+
+    // =========================================================================
+    // ANT getters and setters
+    /**
+     * <p>Set the package name for the generated files.  This is called by ANT.</p>
+     * 
+     * @param  packageName the name of the package for the generated files
+     */
+    public void setPackage(String packageName)
+    {
+        log( ("Setting package name to: " + packageName), Project.MSG_VERBOSE);
+        this.packageName = packageName;
+    }
+
+    /**
+     * <p>Set the output directory.  This is called by ANT.</p>
+     * 
+     * @param  directory the output directory
+     */
+    public void setOutputDir(String directory)
+    {
+        log( ("Setting output directory to: " + directory), 
+              Project.MSG_VERBOSE);
+        this.outputDirectory = directory;
+    }
+
+    /**
+     * <p>Add a header file to the list.  This is called by ANT for a nested
+     * element.</p>
+     * 
+     * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+     */
+    public PatternSet.NameEntry createHeader()
+    {
+        return headerSet.createInclude();
+    }
+
+    /**
+     * <p>Add a header file to the list.  This is called by ANT for a nested
+     * element.</p>
+     * 
+     * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+     */
+    public PatternSet.NameEntry createHeadersFile()
+    {
+        return headerSet.createIncludesFile();
+    }
+
+    /**
+     * <p>Set the set of header patterns.  Patterns may be separated by a comma
+     * or a space.  This is called by ANT.</p>
+     *
+     * @param  headers the string containing the header patterns
+     */
+    public void setHeaders(String headers)
+    {
+        headerSet.setIncludes(headers);
+    }
+
+    /**
+     * <p>Add an optional classpath that defines the location of {@link com.sun.gluegen.opengl.BuildStaticGLInfo}
+     * and <code>BuildStaticGLInfo</code>'s dependencies.</p>
+     * 
+     * @returns {@link org.apache.tools.ant.types.Path}
+     */
+     public Path createClasspath()
+     {
+         return glgenCommandline.createClasspath(project).createPath();
+     }
+
+    // =========================================================================
+    /**
+     * <p>Run the task.  This involves validating the set attributes, creating
+     * the command line to be executed and finally executing the command.</p>
+     * 
+     * @see  org.apache.tools.ant.Task#execute()
+     */
+    public void execute() 
+        throws BuildException 
+    {
+        // validate that all of the required attributes have been set
+        validateAttributes();
+        
+        // TODO:  add logic to determine if the generated file needs to be
+        //        regenerated
+        
+        // add the attributes to the CommandlineJava
+        addAttributes();
+
+        log(glgenCommandline.describeCommand(), Project.MSG_VERBOSE);
+        
+        // execute the command and throw on error
+        final int error = execute(glgenCommandline.getCommandline());
+        if(error == 1)
+            throw new BuildException( ("BuildStaticGLInfo returned: " + error), location);
+    }
+
+    /**
+     * <p>Ensure that the user specified all required arguments.</p>
+     * 
+     * @throws BuildException if there are required arguments that are not 
+     *         present or not valid
+     */
+    private void validateAttributes() 
+        throws BuildException
+    {
+        // validate that the package name is set
+        if(!isValid(packageName))
+            throw new BuildException("Invalid package name: " + packageName);
+
+        // validate that the output directory is set
+        // TODO:  switch to file and ensure that it exists
+        if(!isValid(outputDirectory))
+            throw new BuildException("Invalid output directory name: " + outputDirectory);
+            
+        // TODO:  validate that there are headers set
+    }
+
+    /**
+     * <p>Is the specified string valid?  A valid string is non-<code>null</code>
+     * and has a non-zero length.</p>
+     * 
+     * @param  string the string to be tested for validity
+     * @return <code>true</code> if the string is valid.  <code>false</code>
+     *         otherwise. 
+     */
+    private boolean isValid(String string)
+    {
+        // check for null
+        if(string == null)
+            return false;
+            
+        // ensure that the string has a non-zero length
+        // NOTE:  must trim() to remove leading and trailing whitespace
+        if(string.trim().length() < 1)
+            return false;
+            
+        // the string is valid
+        return true;
+    }
+
+    /**
+     * <p>Add all of the attributes to the command line.  They have already
+     * been validated.</p>
+     */
+    private void addAttributes()
+    {
+        // add the package name
+        glgenCommandline.createArgument().setValue(packageName);
+        
+        // add the output directory name
+        glgenCommandline.createArgument().setValue(outputDirectory);
+        
+        // add the header -files- from the FileSet
+        headerSet.setDir(getProject().getBaseDir());
+        DirectoryScanner directoryScanner = headerSet.getDirectoryScanner(getProject());
+        String[] directoryFiles = directoryScanner.getIncludedFiles();
+        for(int i=0; i<directoryFiles.length; i++)
+        {
+            glgenCommandline.createArgument().setValue(directoryFiles[i]);
+        }
+    }
+
+    /** 
+     * <p>Execute {@link com.sun.gluegen.opengl.BuildStaticGLInfo} in a 
+     * forked JVM.</p>
+     * 
+     * @throws BuildException
+     */
+    private int execute(String[] command) 
+        throws BuildException
+    {
+        // create the object that will perform the command execution
+        Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
+                                                           Project.MSG_WARN), 
+                                      null);
+                                      
+        // set the project and command line
+        execute.setAntRun(project);
+        execute.setCommandline(command);
+        execute.setWorkingDirectory( project.getBaseDir() );
+        
+        // execute the command
+        try
+        {
+            return execute.execute();
+        } catch(IOException ioe)
+        {
+            throw new BuildException(ioe, location);
+        }
+    }
+}
diff --git a/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java b/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java
new file mode 100755
index 000000000..4fe81afbb
--- /dev/null
+++ b/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * - Redistribution of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ * - Redistribution in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * 
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * 
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ * 
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.nativesig;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.opengl.*;
+import com.sun.gluegen.procaddress.*;
+
+/** Emitter producing NativeSignature attributes. */
+
+public class NativeSignatureEmitter extends GLEmitter {
+  protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception {
+    // Allow superclass to do most of the work for us
+    List res = super.generateMethodBindingEmitters(sym);
+
+    // Filter out all non-JavaMethodBindingEmitters
+    for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+      FunctionEmitter emitter = (FunctionEmitter) iter.next();
+      if (!(emitter instanceof JavaMethodBindingEmitter)) {
+        iter.remove();
+      }
+    }
+
+    if (res.isEmpty()) {
+      return res;
+    }
+
+    PrintWriter writer = (getConfig().allStatic() ? javaWriter() : javaImplWriter());
+
+    List processed = new ArrayList();
+
+    // First, filter out all emitters going to the "other" (public) writer
+    for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+      FunctionEmitter emitter = (FunctionEmitter) iter.next();
+      if (emitter.getDefaultOutput() != writer) {
+        processed.add(emitter);
+        iter.remove();
+      }
+    }
+
+    // Now process all of the remaining emitters sorted by MethodBinding
+    while (!res.isEmpty()) {
+      List emittersForBinding = new ArrayList();
+      JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) res.remove(0);
+      emittersForBinding.add(emitter);
+      MethodBinding binding = emitter.getBinding();
+      for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+        JavaMethodBindingEmitter emitter2 = (JavaMethodBindingEmitter) iter.next();
+        if (emitter2.getBinding() == binding) {
+          emittersForBinding.add(emitter2);
+          iter.remove();
+        }
+      }
+      generateNativeSignatureEmitters(binding, emittersForBinding);
+      processed.addAll(emittersForBinding);
+    }
+
+    return processed;
+  }
+
+  protected void generateNativeSignatureEmitters(MethodBinding binding,
+                                                 List allEmitters) {
+    if (allEmitters.isEmpty()) {
+      return;
+    }
+
+    PrintWriter writer = (getConfig().allStatic() ? javaWriter() : javaImplWriter());
+    
+    // Give ourselves the chance to interpose on the generation of all code to keep things simple
+    List newEmitters = new ArrayList();
+    for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+      JavaMethodBindingEmitter javaEmitter = (JavaMethodBindingEmitter) iter.next();
+      NativeSignatureJavaMethodBindingEmitter newEmitter = null;
+      if (javaEmitter instanceof GLJavaMethodBindingEmitter) {
+        newEmitter = new NativeSignatureJavaMethodBindingEmitter((GLJavaMethodBindingEmitter) javaEmitter);
+      } else if (javaEmitter instanceof ProcAddressJavaMethodBindingEmitter) {
+        newEmitter = new NativeSignatureJavaMethodBindingEmitter((ProcAddressJavaMethodBindingEmitter) javaEmitter);
+      } else {
+        newEmitter = new NativeSignatureJavaMethodBindingEmitter(javaEmitter, this);
+      }
+      newEmitters.add(newEmitter);
+    }
+    allEmitters.clear();
+    allEmitters.addAll(newEmitters);
+
+    // Detect whether we need to produce more or modify some of these emitters.
+    // Note that at this point we are assuming that generatePublicEmitters has
+    // been called with signatureOnly both true and false.
+    if (signatureContainsStrings(binding) &&
+        !haveEmitterWithBody(allEmitters)) {
+      // This basically handles glGetString but also any similar methods
+      NativeSignatureJavaMethodBindingEmitter javaEmitter = findEmitterWithWriter(allEmitters, writer);
+
+      // First, we need to clone this emitter to produce the native
+      // entry point
+      NativeSignatureJavaMethodBindingEmitter emitter =
+        new NativeSignatureJavaMethodBindingEmitter(javaEmitter);
+      emitter.removeModifier(JavaMethodBindingEmitter.PUBLIC);
+      emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
+      emitter.setForImplementingMethodCall(true);
+      // Note: this is chosen so we don't have to change the logic in
+      // emitReturnVariableSetupAndCall which decides which variant
+      // (direct / indirect) to call
+      emitter.setForDirectBufferImplementation(true);
+      allEmitters.add(emitter);
+
+      // Now make the original emitter non-native and cause it to emit a body
+      javaEmitter.removeModifier(JavaMethodBindingEmitter.NATIVE);
+      javaEmitter.setEmitBody(true);
+    }
+  }
+
+  protected boolean signatureContainsStrings(MethodBinding binding) {
+    for (int i = 0; i < binding.getNumArguments(); i++) {
+      JavaType type = binding.getJavaArgumentType(i);
+      if (type.isString() || type.isStringArray()) {
+        return true;
+      }
+    }
+    JavaType retType = binding.getJavaReturnType();
+    if (retType.isString() || retType.isStringArray()) {
+      return true;
+    }
+    return false;
+  }
+
+  protected boolean haveEmitterWithBody(List allEmitters) {
+    for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+      JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) iter.next();
+      if (!emitter.signatureOnly()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  protected NativeSignatureJavaMethodBindingEmitter findEmitterWithWriter(List allEmitters, PrintWriter writer) {
+    for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+      NativeSignatureJavaMethodBindingEmitter emitter =
+        (NativeSignatureJavaMethodBindingEmitter) iter.next();
+      if (emitter.getDefaultOutput() == writer) {
+        return emitter;
+      }
+    }
+    throw new RuntimeException("Unexpectedly failed to find an emitter with the given writer");
+  }    
+}
diff --git a/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java
new file mode 100755
index 000000000..12a6c0e4c
--- /dev/null
+++ b/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * - Redistribution of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ * - Redistribution in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * 
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * 
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ * 
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.nativesig;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.cgram.*;
+import com.sun.gluegen.opengl.*;
+import com.sun.gluegen.procaddress.*;
+
+public class NativeSignatureJavaMethodBindingEmitter extends GLJavaMethodBindingEmitter {
+  public NativeSignatureJavaMethodBindingEmitter(GLJavaMethodBindingEmitter methodToWrap) {
+    super(methodToWrap);
+  }
+
+  public NativeSignatureJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap) {
+    super(methodToWrap, false);
+  }
+
+  public NativeSignatureJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap,
+                                                 NativeSignatureEmitter emitter) {
+    super(methodToWrap, false, null, false, false, emitter);
+  }
+
+  protected void emitSignature(PrintWriter writer) {
+    writer.print(getBaseIndentString());
+    emitNativeSignatureAnnotation(writer);
+    super.emitSignature(writer);
+  }
+
+  protected void emitNativeSignatureAnnotation(PrintWriter writer) {
+    if (hasModifier(JavaMethodBindingEmitter.NATIVE)) {
+      // Emit everything as a leaf for now
+      // FIXME: make this configurable
+      writer.print("@NativeSignature(\"l");
+      MethodBinding binding = getBinding();
+      if (callThroughProcAddress) {
+        writer.print("p");
+      }
+      writer.print("(");
+      if (callThroughProcAddress) {
+        writer.print("P");
+      }
+      for (int i = 0; i < binding.getNumArguments(); i++) {
+        emitNativeSignatureElement(writer, binding.getJavaArgumentType(i), binding.getCArgumentType(i), i);
+      }
+      writer.print(")");
+      emitNativeSignatureElement(writer, binding.getJavaReturnType(), binding.getCReturnType(), -1);
+      writer.println("\")");
+    }
+  }
+
+  protected void emitNativeSignatureElement(PrintWriter writer, JavaType type, Type cType, int index) {
+    if (type.isVoid()) {
+      if (index > 0) {
+        throw new InternalError("Error parsing arguments -- void should not be seen aside from argument 0");
+      }
+      return;
+    }
+
+    if (type.isNIOBuffer()) {
+      writer.print("A");
+    } else if (type.isPrimitiveArray()) {
+      writer.print("MO");
+    } else if (type.isPrimitive()) {
+      Class clazz = type.getJavaClass();
+      if      (clazz == Byte.TYPE)      { writer.print("B"); }
+      else if (clazz == Character.TYPE) { writer.print("C"); }
+      else if (clazz == Double.TYPE)    { writer.print("D"); }
+      else if (clazz == Float.TYPE)     { writer.print("F"); }
+      else if (clazz == Integer.TYPE)   { writer.print("I"); }
+      else if (clazz == Long.TYPE)      {
+        // See if this is intended to be a pointer at the C level
+        if (cType.isPointer()) {
+          writer.print("A");
+        } else {
+          writer.print("J");
+        }
+      }
+      else if (clazz == Short.TYPE)     { writer.print("S"); }
+      else if (clazz == Boolean.TYPE)   { writer.print("Z"); }
+      else throw new InternalError("Unhandled primitive type " + clazz);
+    } else if (type.isString()) {
+      writer.print("A");
+    } else {
+      throw new RuntimeException("Type not yet handled: " + type);
+    }
+  }
+
+  protected String getReturnTypeString(boolean skipArray) {
+    if (isForImplementingMethodCall()) {
+      JavaType returnType = getBinding().getJavaReturnType();
+      if (returnType.isString() || returnType.isNIOByteBuffer()) {
+        // Treat these as addresses
+        return "long";
+      }
+    }
+    return super.getReturnTypeString(skipArray);
+  }
+
+  protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+    super.emitPreCallSetup(binding, writer);
+    for (int i = 0; i < binding.getNumArguments(); i++) {
+      JavaType type = binding.getJavaArgumentType(i);
+      if (type.isNIOBuffer() && !directNIOOnly) {
+        // Emit declarations for variables holding primitive arrays as type Object
+        // We don't know 100% sure we're going to use these at this point in the code, though
+        writer.println("  Object " + getNIOBufferArrayName(i) + " = (_direct ? null : BufferFactory.getArray(" +
+                       getArgumentName(i) + "));");
+      } else if (type.isString()) {
+        writer.println("    long " + binding.getArgumentName(i) + "_c_str = BufferFactoryInternal.newCString(" + binding.getArgumentName(i) + ");");
+      }
+      // FIXME: going to need more of these for Buffer[] and String[], at least
+    }
+  }
+
+  protected String getNIOBufferArrayName(int argNumber) {
+    return "__buffer_array_" + argNumber;
+  }
+
+  protected int emitArguments(PrintWriter writer)
+  {
+    boolean needComma = false;
+    int numEmitted = 0;
+
+    if (callThroughProcAddress) {
+      if (changeNameAndArguments) {
+        writer.print("long procAddress");
+        ++numEmitted;
+        needComma = true;
+      }
+    }
+
+    if (forImplementingMethodCall && binding.hasContainingType()) {
+      if (needComma) {
+        writer.print(", ");
+      }
+
+      // Always emit outgoing "this" argument
+      writer.print("long ");
+      writer.print(javaThisArgumentName());      
+      ++numEmitted;
+      needComma = true;
+    }
+
+    for (int i = 0; i < binding.getNumArguments(); i++) {
+      JavaType type = binding.getJavaArgumentType(i);
+      if (type.isVoid()) { 
+        // Make sure this is the only param to the method; if it isn't,
+        // there's something wrong with our parsing of the headers.
+        if (binding.getNumArguments() != 1) {
+          throw new InternalError(
+            "\"void\" argument type found in " +
+            "multi-argument function \"" + binding + "\"");
+        }
+        continue;
+      } 
+
+      if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+        // Don't need to expose these at the Java level
+        continue;
+      }
+
+      if (needComma) {
+        writer.print(", ");
+      }
+
+      if (forImplementingMethodCall &&
+          (forDirectBufferImplementation && type.isNIOBuffer() ||
+           type.isString())) {
+        // Direct Buffers and Strings go out as longs
+        writer.print("long");
+        // FIXME: will need more tests here to handle other constructs like String and direct Buffer arrays
+      } else {
+        writer.print(erasedTypeString(type, false));
+      }
+      writer.print(" ");
+      writer.print(getArgumentName(i));
+
+      ++numEmitted;
+      needComma = true;
+
+      // Add Buffer and array index offset arguments after each associated argument
+      if (forIndirectBufferAndArrayImplementation) {
+        if (type.isNIOBuffer()) {
+          writer.print(", int " + byteOffsetArgName(i));
+        } else if (type.isNIOBufferArray()) {
+          writer.print(", int[] " + 
+                       byteOffsetArrayArgName(i));
+        }
+      }
+
+      // Add offset argument after each primitive array
+      if (type.isPrimitiveArray()) {
+        writer.print(", int " + offsetArgName(i));
+      }
+    }
+    return numEmitted;
+  }
+
+  protected void emitReturnVariableSetupAndCall(MethodBinding binding, PrintWriter writer) {
+    writer.print("    ");
+    JavaType returnType = binding.getJavaReturnType();
+    boolean needsResultAssignment = false;
+
+    if (!returnType.isVoid()) {
+      if (returnType.isCompoundTypeWrapper() ||
+          returnType.isNIOByteBuffer()) {
+        writer.println("java.nio.ByteBuffer _res;");
+        needsResultAssignment = true;
+      } else if (returnType.isArrayOfCompoundTypeWrappers()) {
+        writer.println("java.nio.ByteBuffer[] _res;");
+        needsResultAssignment = true;
+      } else if (returnType.isString() || returnType.isNIOByteBuffer()) {
+        writer.print(returnType);
+        writer.println(" _res;");
+        needsResultAssignment = true;
+      } else {
+        // Always assign to "_res" variable so we can clean up
+        // outgoing String arguments, for example
+        emitReturnType(writer);
+        writer.println(" _res;");
+        needsResultAssignment = true;
+      }
+    }
+
+    if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+      // Must generate two calls for this gated on whether the NIO
+      // buffers coming in are all direct or indirect
+      writer.println("if (_direct) {");
+      writer.print  ("    ");
+    }
+
+    if (needsResultAssignment) {
+      writer.print("  _res = ");
+      if (returnType.isString()) {
+        writer.print("BufferFactoryInternal.newJavaString(");
+      } else if (returnType.isNIOByteBuffer()) {
+        writer.print("BufferFactoryInternal.newDirectByteBuffer(");
+      }
+    } else {
+      writer.print("  ");
+      if (!returnType.isVoid()) {
+        writer.print("return ");
+      }
+    }
+
+    if (binding.signatureUsesJavaPrimitiveArrays() &&
+        !binding.signatureCanUseIndirectNIO()) {
+      // FIXME: what happens with a C function of the form
+      //  void foo(int* arg0, void* arg1);
+      // ?
+
+      // Only one call being made in this body, going to indirect
+      // buffer / array entry point
+      emitCall(binding, writer, false);
+      if (returnType.isString() || returnType.isNIOByteBuffer()) {
+        writer.print(")");
+      }
+      writer.print(";");
+      writer.println();
+    } else {
+      emitCall(binding, writer, true);
+      if (returnType.isString() || returnType.isNIOByteBuffer()) {
+        writer.print(")");
+      }
+      writer.print(";");
+    }
+
+    if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+      // Must generate two calls for this gated on whether the NIO
+      // buffers coming in are all direct or indirect
+      writer.println();
+      writer.println("    } else {");
+      writer.print  ("    ");
+      if (needsResultAssignment) {
+        writer.print("    _res = ");
+      } else {
+        writer.print("  ");
+        if (!returnType.isVoid()) {
+          writer.print("return ");
+        }
+      }
+      emitCall(binding, writer, false);
+      writer.print(";");
+      writer.println();
+      writer.println("    }");
+    } else {
+      writer.println();
+    }
+    emitPrologueOrEpilogue(epilogue, writer);
+    if (needsResultAssignment) {
+      emitCallResultReturn(binding, writer);
+    }
+  }
+
+  protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean direct) {
+    // Note that we override this completely because we both need to
+    // move the potential location of the outgoing proc address as
+    // well as change the way we pass out Buffers, arrays, Strings, etc.
+
+    boolean needComma = false;
+    int numArgsEmitted = 0;
+
+    if (callThroughProcAddress) {
+      writer.print("__addr_");
+      needComma = true;
+      ++numArgsEmitted;
+    }
+
+    if (binding.hasContainingType()) {
+      // Emit this pointer
+      assert(binding.getContainingType().isCompoundTypeWrapper());
+      writer.print("BufferFactoryInternal.getDirectBufferAddress(");
+      writer.print("getBuffer()");
+      writer.print(")");
+      needComma = true;
+      ++numArgsEmitted;
+    }
+    for (int i = 0; i < binding.getNumArguments(); i++) {
+      JavaType type = binding.getJavaArgumentType(i);
+      if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+        // Don't need to expose these at the Java level
+        continue;
+      }
+
+      if (type.isVoid()) {
+        // Make sure this is the only param to the method; if it isn't,
+        // there's something wrong with our parsing of the headers.
+        assert(binding.getNumArguments() == 1);
+        continue;
+      } 
+
+      if (needComma) {
+        writer.print(", ");
+      }
+
+      if (type.isCompoundTypeWrapper()) {
+        writer.print("BufferFactoryInternal.getDirectBufferAddress(");
+        writer.print("((");
+      }
+
+      if (type.isNIOBuffer()) {
+        if (!direct) {
+          writer.print(getNIOBufferArrayName(i));
+        } else {
+          writer.print("BufferFactoryInternal.getDirectBufferAddress(");
+          writer.print(getArgumentName(i));
+          writer.print(")");
+        }
+      } else {
+        writer.print(getArgumentName(i));
+      }
+
+      if (type.isCompoundTypeWrapper()) {
+        writer.print(" == null) ? null : ");
+        writer.print(getArgumentName(i));
+        writer.print(".getBuffer())");
+        writer.print(")");
+      }
+
+      if (type.isNIOBuffer()) {
+        if (direct) {
+          writer.print("+ BufferFactory.getDirectBufferByteOffset(" + getArgumentName(i) + ")");
+        } else {
+          writer.print(", BufferFactoryInternal.arrayBaseOffset(" +
+                       getNIOBufferArrayName(i) +
+                       ") + BufferFactory.getIndirectBufferByteOffset(" + getArgumentName(i) + ")");
+        }
+      } else if (type.isNIOBufferArray()) {
+        writer.print(", " + byteOffsetArrayArgName(i));
+      }
+
+      // Add Array offset parameter for primitive arrays
+      if (type.isPrimitiveArray()) {
+        writer.print(", ");
+        writer.print("BufferFactoryInternal.arrayBaseOffset(" + getArgumentName(i) + ") + ");
+        if(type.isFloatArray()) {
+          writer.print("BufferFactory.SIZEOF_FLOAT * ");
+        } else if(type.isDoubleArray()) {
+          writer.print("BufferFactory.SIZEOF_DOUBLE * ");
+        } else if(type.isByteArray()) {
+          writer.print("1 * ");
+        } else if(type.isLongArray()) {
+          writer.print("BufferFactory.SIZEOF_LONG * ");
+        } else if(type.isShortArray()) {
+          writer.print("BufferFactory.SIZEOF_SHORT * ");
+        } else if(type.isIntArray()) {
+          writer.print("BufferFactory.SIZEOF_INT * ");
+        } else {
+          throw new RuntimeException("Unsupported type for calculating array offset argument for " +
+                                     getArgumentName(i) +
+                                     "-- error occurred while processing Java glue code for " + getName());
+        }
+        writer.print(offsetArgName(i));
+      }
+
+      if (type.isString()) {
+        writer.print("_c_str");
+      }
+
+      if (type.isCompoundTypeWrapper()) {
+        writer.print(")");
+      }
+
+      needComma = true;
+      ++numArgsEmitted;
+    }
+    return numArgsEmitted;
+  }
+
+  protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) {
+    for (int i = 0; i < binding.getNumArguments(); i++) {
+      JavaType type = binding.getJavaArgumentType(i);
+      if (type.isString()) {
+        writer.println(";");
+        writer.println("    BufferFactoryInternal.freeCString(" + binding.getArgumentName(i) + "_c_str);");
+      }
+      // FIXME: will need more of these cleanups for things like Buffer[] and String[] (see above)
+    }
+
+    super.emitCallResultReturn(binding, writer);
+  }
+
+  public String getName() {
+    String res = super.getName();
+    if (forImplementingMethodCall && bufferObjectVariant) {
+      return res + "BufObj";
+    }
+    return res;
+  }
+
+  protected String getImplMethodName(boolean direct) {
+    String name = null;
+    if (direct) {
+      name = binding.getRenamedMethodName() + "$0";
+    } else {
+      name = binding.getRenamedMethodName() + "$1";
+    }
+    if (bufferObjectVariant) {
+      return name + "BufObj";
+    }
+    return name;
+  }
+}
-- 
cgit v1.2.3