/* * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package com.sun.tools.javah; import java.io.UnsupportedEncodingException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import com.sun.javadoc.*; import java.io.*; import java.util.Stack; import java.util.Vector; import java.util.Arrays; /** * An abstraction for generating support files required by native methods. * Subclasses are for specific native interfaces. At the time of its * original writing, this interface is rich enough to support JNI and the * old 1.0-style native method interface. * * @author Sucheta Dambalkar(Revised) */ public abstract class Gen { protected String lineSep = System.getProperty("line.separator"); RootDoc root; /* * List of classes for which we must generate output. */ protected ClassDoc[] classes; static private final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); public Gen(RootDoc root){ this.root = root; } /** * Override this abstract method, generating content for the named * class into the outputstream. */ protected abstract void write(OutputStream o, ClassDoc clazz) throws ClassNotFoundException; /** * Override this method to provide a list of #include statements * required by the native interface. */ protected abstract String getIncludes(); /* * Output location. */ protected String outDir; protected String outFile; public void setOutDir(String outDir) { /* Check important, otherwise concatenation of two null strings * produces the "nullnull" String. */ if (outDir != null) { this.outDir = outDir + System.getProperty("file.separator"); File d = new File(outDir); if (!d.exists()) if (!d.mkdirs()) Util.error("cant.create.dir", d.toString()); } } public void setOutFile(String outFile) { this.outFile = outFile; } public void setClasses(ClassDoc[] classes) { this.classes = classes; } /* * Smartness with generated files. */ protected boolean force = false; public void setForce(boolean state) { force = state; } /** * We explicitly need to write ASCII files because that is what C * compilers understand. */ protected PrintWriter wrapWriter(OutputStream o) { try { return new PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true); } catch (UnsupportedEncodingException use) { Util.bug("encoding.iso8859_1.not.found"); return null; /* dead code */ } } /** * After initializing state of an instance, use this method to start * processing. * * Buffer size chosen as an approximation from a single sampling of: * expr `du -sk` / `ls *.h | wc -l` */ public void run() throws IOException, ClassNotFoundException { int i = 0; if (outFile != null) { /* Everything goes to one big file... */ ByteArrayOutputStream bout = new ByteArrayOutputStream(8192); writeFileTop(bout); /* only once */ for (i = 0; i < classes.length; i++) { write(bout, classes[i]); } writeIfChanged(bout.toByteArray(), outFile); } else { /* Each class goes to its own file... */ for (i = 0; i < classes.length; i++) { ByteArrayOutputStream bout = new ByteArrayOutputStream(8192); writeFileTop(bout); ClassDoc clazz = classes[i]; write(bout, clazz); writeIfChanged(bout.toByteArray(), getFileName(clazz.qualifiedName())); } } } /* * Write the contents of byte[] b to a file named file. Writing * is done if either the file doesn't exist or if the contents are * different. */ private void writeIfChanged(byte[] b, String file) throws IOException { File f = new File(file); boolean mustWrite = false; String event = "[No need to update file "; if (force) { mustWrite = true; event = "[Forcefully writing file "; } else { if (!f.exists()) { mustWrite = true; event = "[Creating file "; } else { int l = (int)f.length(); if (b.length != l) { mustWrite = true; event = "[Overwriting file "; } else { /* Lengths are equal, so read it. */ byte[] a = new byte[l]; FileInputStream in = new FileInputStream(f); if (in.read(a) != l) { in.close(); /* This can't happen, we already checked the length. */ Util.error("not.enough.bytes", Integer.toString(l), f.toString()); } in.close(); while (--l >= 0) { if (a[l] != b[l]) { mustWrite = true; event = "[Overwriting file "; } } } } } if (Util.verbose) Util.log(event + file + "]"); if (mustWrite) { OutputStream out = new FileOutputStream(file); out.write(b); /* No buffering, just one big write! */ out.close(); } } protected String defineForStatic(ClassDoc c, FieldDoc f){ String cnamedoc = c.qualifiedName(); String fnamedoc = f.name(); String cname = Mangle.mangle(cnamedoc, Mangle.Type.CLASS); String fname = Mangle.mangle(fnamedoc, Mangle.Type.FIELDSTUB); if (!f.isStatic()) Util.bug("tried.to.define.non.static"); if (f.isFinal()) { Object value = null; value = f.constantValue(); if (value != null) { /* so it is a ConstantExpression */ String constString = null; if ((value instanceof Integer) || (value instanceof Byte) || (value instanceof Character) || (value instanceof Short) || (value instanceof Boolean)) { /* covers byte, boolean, char, short, int */ if(value instanceof Boolean) constString = (value.toString() == "true") ? "1L" : "0L"; else constString = value.toString() + "L"; } else if (value instanceof Long) { // Visual C++ supports the i64 suffix, not LL. if (isWindows) constString = value.toString() + "i64"; else constString = value.toString() + "LL"; } else if (value instanceof Float) { /* bug for bug */ float fv = ((Float)value).floatValue(); if (Float.isInfinite(fv)) constString = ((fv < 0) ? "-" : "") + "Inff"; else constString = value.toString() + "f"; } else if (value instanceof Double) { /* bug for bug */ double d = ((Double)value).doubleValue(); if (Double.isInfinite(d)) constString = ((d < 0) ? "-" : "") + "InfD"; else constString = value.toString(); } if (constString != null) { StringBuffer s = new StringBuffer("#undef "); s.append(cname); s.append("_"); s.append(fname); s.append(lineSep); s.append("#define "); s.append(cname); s.append("_"); s.append(fname); s.append(" "); s.append(constString); return s.toString(); } } } return null; } /* * Deal with the C pre-processor. */ protected String cppGuardBegin() { return "#ifdef __cplusplus" + lineSep + "extern \"C\" {" + lineSep + "#endif"; } protected String cppGuardEnd() { return "#ifdef __cplusplus" + lineSep + "}" + lineSep + "#endif"; } protected String guardBegin(String cname) { return "/* Header for class " + cname + " */" + lineSep + lineSep + "#ifndef _Included_" + cname + lineSep + "#define _Included_" + cname; } protected String guardEnd(String cname) { return "#endif"; } /* * File name and file preamble related operations. */ protected void writeFileTop(OutputStream o) { PrintWriter pw = wrapWriter(o); pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep + getIncludes()); } protected String baseFileName(String clazz) { StringBuffer f = new StringBuffer(Mangle.mangle(clazz, Mangle.Type.CLASS)); if (outDir != null) { f.insert(0, outDir); } return f.toString(); } protected String getFileName(String clazz) { return baseFileName(clazz) + getFileSuffix(); } protected String getFileSuffix() { return ".h"; } /** * Including super classes' fields. */ FieldDoc[] getAllFields(ClassDoc subclazz) throws ClassNotFoundException { Vector fields = new Vector(); ClassDoc cd = null; Stack s = new Stack(); cd = subclazz; while (true) { s.push(cd); ClassDoc c = cd.superclass(); if (c == null) break; cd = c; } while (!s.empty()) { cd = (ClassDoc)s.pop(); fields.addAll(Arrays.asList(cd.fields())); } return (FieldDoc[]) fields.toArray(new FieldDoc[fields.size()]); } }