0N/A/*
553N/A * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
553N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
553N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
553N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
553N/A * or visit www.oracle.com if you need additional information or have any
553N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.tools.javah;
0N/A
0N/Aimport java.io.UnsupportedEncodingException;
0N/Aimport java.io.ByteArrayOutputStream;
415N/Aimport java.io.FileNotFoundException;
0N/Aimport java.io.IOException;
415N/Aimport java.io.InputStream;
0N/Aimport java.io.OutputStream;
415N/Aimport java.io.OutputStreamWriter;
0N/Aimport java.io.PrintWriter;
415N/Aimport java.util.ArrayList;
415N/Aimport java.util.Arrays;
415N/Aimport java.util.List;
415N/Aimport java.util.Set;
0N/Aimport java.util.Stack;
415N/A
415N/Aimport javax.annotation.processing.ProcessingEnvironment;
0N/A
415N/Aimport javax.lang.model.element.ExecutableElement;
415N/Aimport javax.lang.model.element.Modifier;
415N/Aimport javax.lang.model.element.TypeElement;
415N/Aimport javax.lang.model.element.VariableElement;
415N/Aimport javax.lang.model.util.ElementFilter;
415N/Aimport javax.lang.model.util.Elements;
415N/Aimport javax.lang.model.util.Types;
415N/A
415N/Aimport javax.tools.FileObject;
415N/Aimport javax.tools.JavaFileManager;
415N/Aimport javax.tools.JavaFileObject;
415N/Aimport javax.tools.StandardLocation;
0N/A
0N/A/**
0N/A * An abstraction for generating support files required by native methods.
0N/A * Subclasses are for specific native interfaces. At the time of its
0N/A * original writing, this interface is rich enough to support JNI and the
0N/A * old 1.0-style native method interface.
0N/A *
580N/A * <p><b>This is NOT part of any supported API.
415N/A * If you write code that depends on this, you do so at your own
415N/A * risk. This code and its internal interfaces are subject to change
415N/A * or deletion without notice.</b></p>
415N/A *
0N/A * @author Sucheta Dambalkar(Revised)
0N/A */
0N/Apublic abstract class Gen {
0N/A protected String lineSep = System.getProperty("line.separator");
0N/A
415N/A protected ProcessingEnvironment processingEnvironment;
415N/A protected Types types;
415N/A protected Elements elems;
415N/A protected Mangle mangler;
415N/A protected Util util;
415N/A
415N/A protected Gen(Util util) {
415N/A this.util = util;
415N/A }
415N/A
0N/A /*
0N/A * List of classes for which we must generate output.
0N/A */
415N/A protected Set<TypeElement> classes;
0N/A static private final boolean isWindows =
0N/A System.getProperty("os.name").startsWith("Windows");
0N/A
0N/A
0N/A /**
0N/A * Override this abstract method, generating content for the named
0N/A * class into the outputstream.
0N/A */
415N/A protected abstract void write(OutputStream o, TypeElement clazz) throws Util.Exit;
0N/A
0N/A /**
0N/A * Override this method to provide a list of #include statements
0N/A * required by the native interface.
0N/A */
0N/A protected abstract String getIncludes();
0N/A
0N/A /*
0N/A * Output location.
0N/A */
415N/A protected JavaFileManager fileManager;
415N/A protected JavaFileObject outFile;
0N/A
415N/A public void setFileManager(JavaFileManager fm) {
415N/A fileManager = fm;
0N/A }
0N/A
415N/A public void setOutFile(JavaFileObject outFile) {
0N/A this.outFile = outFile;
0N/A }
0N/A
0N/A
415N/A public void setClasses(Set<TypeElement> classes) {
0N/A this.classes = classes;
0N/A }
0N/A
415N/A void setProcessingEnvironment(ProcessingEnvironment pEnv) {
415N/A processingEnvironment = pEnv;
415N/A elems = pEnv.getElementUtils();
415N/A types = pEnv.getTypeUtils();
415N/A mangler = new Mangle(elems, types);
415N/A }
415N/A
0N/A /*
0N/A * Smartness with generated files.
0N/A */
0N/A protected boolean force = false;
0N/A
0N/A public void setForce(boolean state) {
0N/A force = state;
0N/A }
0N/A
0N/A /**
0N/A * We explicitly need to write ASCII files because that is what C
0N/A * compilers understand.
0N/A */
415N/A protected PrintWriter wrapWriter(OutputStream o) throws Util.Exit {
0N/A try {
415N/A return new PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true);
0N/A } catch (UnsupportedEncodingException use) {
415N/A util.bug("encoding.iso8859_1.not.found");
0N/A return null; /* dead code */
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * After initializing state of an instance, use this method to start
0N/A * processing.
0N/A *
0N/A * Buffer size chosen as an approximation from a single sampling of:
0N/A * expr `du -sk` / `ls *.h | wc -l`
0N/A */
415N/A public void run() throws IOException, ClassNotFoundException, Util.Exit {
0N/A int i = 0;
0N/A if (outFile != null) {
0N/A /* Everything goes to one big file... */
0N/A ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
0N/A writeFileTop(bout); /* only once */
0N/A
415N/A for (TypeElement t: classes) {
415N/A write(bout, t);
0N/A }
0N/A
0N/A writeIfChanged(bout.toByteArray(), outFile);
0N/A } else {
0N/A /* Each class goes to its own file... */
415N/A for (TypeElement t: classes) {
0N/A ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
0N/A writeFileTop(bout);
415N/A write(bout, t);
415N/A writeIfChanged(bout.toByteArray(), getFileObject(t.getQualifiedName()));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Write the contents of byte[] b to a file named file. Writing
0N/A * is done if either the file doesn't exist or if the contents are
0N/A * different.
0N/A */
415N/A private void writeIfChanged(byte[] b, FileObject file) throws IOException {
0N/A boolean mustWrite = false;
0N/A String event = "[No need to update file ";
0N/A
0N/A if (force) {
0N/A mustWrite = true;
0N/A event = "[Forcefully writing file ";
0N/A } else {
415N/A InputStream in;
415N/A byte[] a;
415N/A try {
415N/A // regrettably, there's no API to get the length in bytes
415N/A // for a FileObject, so we can't short-circuit reading the
415N/A // file here
415N/A in = file.openInputStream();
415N/A a = readBytes(in);
415N/A if (!Arrays.equals(a, b)) {
0N/A mustWrite = true;
0N/A event = "[Overwriting file ";
415N/A
0N/A }
415N/A } catch (FileNotFoundException e) {
415N/A mustWrite = true;
415N/A event = "[Creating file ";
0N/A }
0N/A }
415N/A
415N/A if (util.verbose)
415N/A util.log(event + file + "]");
415N/A
0N/A if (mustWrite) {
415N/A OutputStream out = file.openOutputStream();
0N/A out.write(b); /* No buffering, just one big write! */
0N/A out.close();
0N/A }
0N/A }
0N/A
415N/A protected byte[] readBytes(InputStream in) throws IOException {
415N/A try {
415N/A byte[] array = new byte[in.available() + 1];
415N/A int offset = 0;
415N/A int n;
415N/A while ((n = in.read(array, offset, array.length - offset)) != -1) {
415N/A offset += n;
415N/A if (offset == array.length)
415N/A array = Arrays.copyOf(array, array.length * 2);
415N/A }
0N/A
415N/A return Arrays.copyOf(array, offset);
415N/A } finally {
415N/A in.close();
415N/A }
415N/A }
0N/A
415N/A protected String defineForStatic(TypeElement c, VariableElement f)
415N/A throws Util.Exit {
415N/A CharSequence cnamedoc = c.getQualifiedName();
415N/A CharSequence fnamedoc = f.getSimpleName();
0N/A
415N/A String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
415N/A String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
415N/A
415N/A if (!f.getModifiers().contains(Modifier.STATIC))
415N/A util.bug("tried.to.define.non.static");
415N/A
415N/A if (f.getModifiers().contains(Modifier.FINAL)) {
0N/A Object value = null;
0N/A
415N/A value = f.getConstantValue();
0N/A
0N/A if (value != null) { /* so it is a ConstantExpression */
0N/A String constString = null;
0N/A if ((value instanceof Integer)
0N/A || (value instanceof Byte)
415N/A || (value instanceof Short)) {
415N/A /* covers byte, short, int */
415N/A constString = value.toString() + "L";
415N/A } else if (value instanceof Boolean) {
415N/A constString = ((Boolean) value) ? "1L" : "0L";
415N/A } else if (value instanceof Character) {
415N/A Character ch = (Character) value;
415N/A constString = String.valueOf(((int) ch) & 0xffff) + "L";
0N/A } else if (value instanceof Long) {
0N/A // Visual C++ supports the i64 suffix, not LL.
0N/A if (isWindows)
0N/A constString = value.toString() + "i64";
0N/A else
0N/A constString = value.toString() + "LL";
0N/A } else if (value instanceof Float) {
0N/A /* bug for bug */
0N/A float fv = ((Float)value).floatValue();
0N/A if (Float.isInfinite(fv))
0N/A constString = ((fv < 0) ? "-" : "") + "Inff";
0N/A else
0N/A constString = value.toString() + "f";
0N/A } else if (value instanceof Double) {
0N/A /* bug for bug */
0N/A double d = ((Double)value).doubleValue();
0N/A if (Double.isInfinite(d))
0N/A constString = ((d < 0) ? "-" : "") + "InfD";
0N/A else
0N/A constString = value.toString();
0N/A }
0N/A if (constString != null) {
0N/A StringBuffer s = new StringBuffer("#undef ");
0N/A s.append(cname); s.append("_"); s.append(fname); s.append(lineSep);
0N/A s.append("#define "); s.append(cname); s.append("_");
0N/A s.append(fname); s.append(" "); s.append(constString);
0N/A return s.toString();
0N/A }
0N/A
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /*
0N/A * Deal with the C pre-processor.
0N/A */
0N/A protected String cppGuardBegin() {
0N/A return "#ifdef __cplusplus" + lineSep + "extern \"C\" {" + lineSep + "#endif";
0N/A }
0N/A
0N/A protected String cppGuardEnd() {
0N/A return "#ifdef __cplusplus" + lineSep + "}" + lineSep + "#endif";
0N/A }
0N/A
0N/A protected String guardBegin(String cname) {
0N/A return "/* Header for class " + cname + " */" + lineSep + lineSep +
0N/A "#ifndef _Included_" + cname + lineSep +
0N/A "#define _Included_" + cname;
0N/A }
0N/A
0N/A protected String guardEnd(String cname) {
0N/A return "#endif";
0N/A }
0N/A
0N/A /*
0N/A * File name and file preamble related operations.
0N/A */
415N/A protected void writeFileTop(OutputStream o) throws Util.Exit {
0N/A PrintWriter pw = wrapWriter(o);
0N/A pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep +
0N/A getIncludes());
0N/A }
0N/A
415N/A protected String baseFileName(CharSequence className) {
415N/A return mangler.mangle(className, Mangle.Type.CLASS);
0N/A }
0N/A
415N/A protected FileObject getFileObject(CharSequence className) throws IOException {
415N/A String name = baseFileName(className) + getFileSuffix();
415N/A return fileManager.getFileForOutput(StandardLocation.SOURCE_OUTPUT, "", name, null);
0N/A }
0N/A
0N/A protected String getFileSuffix() {
0N/A return ".h";
0N/A }
0N/A
0N/A /**
0N/A * Including super classes' fields.
0N/A */
0N/A
415N/A List<VariableElement> getAllFields(TypeElement subclazz) {
415N/A List<VariableElement> fields = new ArrayList<VariableElement>();
415N/A TypeElement cd = null;
415N/A Stack<TypeElement> s = new Stack<TypeElement>();
0N/A
0N/A cd = subclazz;
0N/A while (true) {
0N/A s.push(cd);
415N/A TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
0N/A if (c == null)
0N/A break;
0N/A cd = c;
0N/A }
0N/A
0N/A while (!s.empty()) {
415N/A cd = s.pop();
415N/A fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
0N/A }
0N/A
415N/A return fields;
415N/A }
415N/A
415N/A // c.f. MethodDoc.signature
415N/A String signature(ExecutableElement e) {
415N/A StringBuffer sb = new StringBuffer("(");
415N/A String sep = "";
415N/A for (VariableElement p: e.getParameters()) {
415N/A sb.append(sep);
415N/A sb.append(types.erasure(p.asType()).toString());
415N/A sep = ",";
415N/A }
415N/A sb.append(")");
415N/A return sb.toString();
0N/A }
0N/A}
415N/A