001: /*
002: * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javah;
027:
028: import java.io.UnsupportedEncodingException;
029: import java.io.ByteArrayOutputStream;
030: import java.io.IOException;
031: import java.io.OutputStream;
032: import java.io.PrintWriter;
033: import com.sun.javadoc.*;
034: import java.io.*;
035: import java.util.Stack;
036: import java.util.Vector;
037: import java.util.Arrays;
038:
039: /**
040: * An abstraction for generating support files required by native methods.
041: * Subclasses are for specific native interfaces. At the time of its
042: * original writing, this interface is rich enough to support JNI and the
043: * old 1.0-style native method interface.
044: *
045: * @author Sucheta Dambalkar(Revised)
046: */
047:
048: public abstract class Gen {
049: protected String lineSep = System.getProperty("line.separator");
050:
051: RootDoc root;
052: /*
053: * List of classes for which we must generate output.
054: */
055: protected ClassDoc[] classes;
056: static private final boolean isWindows = System.getProperty(
057: "os.name").startsWith("Windows");
058:
059: public Gen(RootDoc root) {
060: this .root = root;
061: }
062:
063: /**
064: * Override this abstract method, generating content for the named
065: * class into the outputstream.
066: */
067: protected abstract void write(OutputStream o, ClassDoc clazz)
068: throws ClassNotFoundException;
069:
070: /**
071: * Override this method to provide a list of #include statements
072: * required by the native interface.
073: */
074: protected abstract String getIncludes();
075:
076: /*
077: * Output location.
078: */
079: protected String outDir;
080: protected String outFile;
081:
082: public void setOutDir(String outDir) {
083: /* Check important, otherwise concatenation of two null strings
084: * produces the "nullnull" String.
085: */
086: if (outDir != null) {
087: this .outDir = outDir + System.getProperty("file.separator");
088: File d = new File(outDir);
089: if (!d.exists())
090: if (!d.mkdirs())
091: Util.error("cant.create.dir", d.toString());
092: }
093: }
094:
095: public void setOutFile(String outFile) {
096: this .outFile = outFile;
097: }
098:
099: public void setClasses(ClassDoc[] classes) {
100: this .classes = classes;
101: }
102:
103: /*
104: * Smartness with generated files.
105: */
106: protected boolean force = false;
107:
108: public void setForce(boolean state) {
109: force = state;
110: }
111:
112: /**
113: * We explicitly need to write ASCII files because that is what C
114: * compilers understand.
115: */
116: protected PrintWriter wrapWriter(OutputStream o) {
117: try {
118: return new PrintWriter(new OutputStreamWriter(o,
119: "ISO8859_1"), true);
120: } catch (UnsupportedEncodingException use) {
121: Util.bug("encoding.iso8859_1.not.found");
122: return null; /* dead code */
123: }
124: }
125:
126: /**
127: * After initializing state of an instance, use this method to start
128: * processing.
129: *
130: * Buffer size chosen as an approximation from a single sampling of:
131: * expr `du -sk` / `ls *.h | wc -l`
132: */
133: public void run() throws IOException, ClassNotFoundException {
134: int i = 0;
135: if (outFile != null) {
136: /* Everything goes to one big file... */
137: ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
138: writeFileTop(bout); /* only once */
139:
140: for (i = 0; i < classes.length; i++) {
141: write(bout, classes[i]);
142: }
143:
144: writeIfChanged(bout.toByteArray(), outFile);
145: } else {
146: /* Each class goes to its own file... */
147: for (i = 0; i < classes.length; i++) {
148: ByteArrayOutputStream bout = new ByteArrayOutputStream(
149: 8192);
150: writeFileTop(bout);
151: ClassDoc clazz = classes[i];
152: write(bout, clazz);
153: writeIfChanged(bout.toByteArray(), getFileName(clazz
154: .qualifiedName()));
155: }
156: }
157: }
158:
159: /*
160: * Write the contents of byte[] b to a file named file. Writing
161: * is done if either the file doesn't exist or if the contents are
162: * different.
163: */
164: private void writeIfChanged(byte[] b, String file)
165: throws IOException {
166: File f = new File(file);
167: boolean mustWrite = false;
168: String event = "[No need to update file ";
169:
170: if (force) {
171: mustWrite = true;
172: event = "[Forcefully writing file ";
173: } else {
174: if (!f.exists()) {
175: mustWrite = true;
176: event = "[Creating file ";
177: } else {
178: int l = (int) f.length();
179: if (b.length != l) {
180: mustWrite = true;
181: event = "[Overwriting file ";
182: } else {
183: /* Lengths are equal, so read it. */
184: byte[] a = new byte[l];
185: FileInputStream in = new FileInputStream(f);
186: if (in.read(a) != l) {
187: in.close();
188: /* This can't happen, we already checked the length. */
189: Util.error("not.enough.bytes", Integer
190: .toString(l), f.toString());
191: }
192: in.close();
193: while (--l >= 0) {
194: if (a[l] != b[l]) {
195: mustWrite = true;
196: event = "[Overwriting file ";
197: }
198: }
199: }
200: }
201: }
202: if (Util.verbose)
203: Util.log(event + file + "]");
204: if (mustWrite) {
205: OutputStream out = new FileOutputStream(file);
206: out.write(b); /* No buffering, just one big write! */
207: out.close();
208: }
209: }
210:
211: protected String defineForStatic(ClassDoc c, FieldDoc f) {
212:
213: String cnamedoc = c.qualifiedName();
214: String fnamedoc = f.name();
215:
216: String cname = Mangle.mangle(cnamedoc, Mangle.Type.CLASS);
217: String fname = Mangle.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
218:
219: if (!f.isStatic())
220: Util.bug("tried.to.define.non.static");
221:
222: if (f.isFinal()) {
223: Object value = null;
224:
225: value = f.constantValue();
226:
227: if (value != null) { /* so it is a ConstantExpression */
228: String constString = null;
229: if ((value instanceof Integer)
230: || (value instanceof Byte)
231: || (value instanceof Character)
232: || (value instanceof Short)
233: || (value instanceof Boolean)) {
234: /* covers byte, boolean, char, short, int */
235: if (value instanceof Boolean)
236: constString = (value.toString() == "true") ? "1L"
237: : "0L";
238: else
239: constString = value.toString() + "L";
240: } else if (value instanceof Long) {
241: // Visual C++ supports the i64 suffix, not LL.
242: if (isWindows)
243: constString = value.toString() + "i64";
244: else
245: constString = value.toString() + "LL";
246: } else if (value instanceof Float) {
247: /* bug for bug */
248: float fv = ((Float) value).floatValue();
249: if (Float.isInfinite(fv))
250: constString = ((fv < 0) ? "-" : "") + "Inff";
251: else
252: constString = value.toString() + "f";
253: } else if (value instanceof Double) {
254: /* bug for bug */
255: double d = ((Double) value).doubleValue();
256: if (Double.isInfinite(d))
257: constString = ((d < 0) ? "-" : "") + "InfD";
258: else
259: constString = value.toString();
260: }
261: if (constString != null) {
262: StringBuffer s = new StringBuffer("#undef ");
263: s.append(cname);
264: s.append("_");
265: s.append(fname);
266: s.append(lineSep);
267: s.append("#define ");
268: s.append(cname);
269: s.append("_");
270: s.append(fname);
271: s.append(" ");
272: s.append(constString);
273: return s.toString();
274: }
275:
276: }
277: }
278: return null;
279: }
280:
281: /*
282: * Deal with the C pre-processor.
283: */
284: protected String cppGuardBegin() {
285: return "#ifdef __cplusplus" + lineSep + "extern \"C\" {"
286: + lineSep + "#endif";
287: }
288:
289: protected String cppGuardEnd() {
290: return "#ifdef __cplusplus" + lineSep + "}" + lineSep
291: + "#endif";
292: }
293:
294: protected String guardBegin(String cname) {
295: return "/* Header for class " + cname + " */" + lineSep
296: + lineSep + "#ifndef _Included_" + cname + lineSep
297: + "#define _Included_" + cname;
298: }
299:
300: protected String guardEnd(String cname) {
301: return "#endif";
302: }
303:
304: /*
305: * File name and file preamble related operations.
306: */
307: protected void writeFileTop(OutputStream o) {
308: PrintWriter pw = wrapWriter(o);
309: pw
310: .println("/* DO NOT EDIT THIS FILE - it is machine generated */"
311: + lineSep + getIncludes());
312: }
313:
314: protected String baseFileName(String clazz) {
315: StringBuffer f = new StringBuffer(Mangle.mangle(clazz,
316: Mangle.Type.CLASS));
317: if (outDir != null) {
318: f.insert(0, outDir);
319: }
320: return f.toString();
321: }
322:
323: protected String getFileName(String clazz) {
324: return baseFileName(clazz) + getFileSuffix();
325: }
326:
327: protected String getFileSuffix() {
328: return ".h";
329: }
330:
331: /**
332: * Including super classes' fields.
333: */
334:
335: FieldDoc[] getAllFields(ClassDoc subclazz)
336: throws ClassNotFoundException {
337: Vector fields = new Vector();
338: ClassDoc cd = null;
339: Stack s = new Stack();
340:
341: cd = subclazz;
342: while (true) {
343: s.push(cd);
344: ClassDoc c = cd.super class();
345: if (c == null)
346: break;
347: cd = c;
348: }
349:
350: while (!s.empty()) {
351: cd = (ClassDoc) s.pop();
352: fields.addAll(Arrays.asList(cd.fields()));
353: }
354:
355: return (FieldDoc[]) fields.toArray(new FieldDoc[fields.size()]);
356: }
357: }
|