/* * java-gnome, a UI library for writing GTK and GNOME programs from Java! * * Copyright © 2007-2010 Operational Dynamics Consulting, Pty Ltd * * The code in this file, and the program it is a part of, is made available * to you by its authors as open source software: you can redistribute it * and/or modify it under the terms of the GNU General Public License version * 2 ("GPL") as published by the Free Software Foundation. * * This program 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 GPL for more details. * * You should have received a copy of the GPL along with this program. If not, * see http://www.gnu.org/licenses/. The authors of this program may be * contacted through http://java-gnome.sourceforge.net/. */ import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.operationaldynamics.defsparser.Block; import com.operationaldynamics.defsparser.DefsLineNumberReader; import com.operationaldynamics.defsparser.DefsParser; import com.operationaldynamics.driver.DefsFile; import com.operationaldynamics.driver.ImproperDefsFileException; /** * The java-gnome code generator. * *

* The biggest problem architecturally is transforming information from the * form that the upstream .defs data provides to one we can do something * useful with in our context. The code generator, then is essentially two * separate pieces that have nothing to do with each other: * *

* *

* The link between the two sides are the createThing() and createGenerator() * methods in each Block object; this is where we translate from the * characteristic key names in the .defs data to the names we use in the * generator. * *

* To generate the java-gnome bindings, we therefore do several things: * *

    *
  1. setup: demultiplex the massive monolithic stream of .defs information * into one .defs file per type. This has been done externally ahead of time * before the BindingsGenerator runs. * *
  2. register all the type information: We load each .defs file and create * arrays of Blocks. We then stash these Blocks in an a class called DefsFile. * Along the way we call each Block's createThing() and then Thing.register() * to store the the resultant in our lookup table [Obviously this only * concerns (define-...) blocks which declare type information (the TypeBlock * subclasses)]. * *
  3. with a full database of type information in hand, we can then do an * iteration over the Block arrays to actually generate the code that goes * with each stanza. We get the appropriate Generator object by calling each * Block's createGenerator() method and then run its writeTranslationCode() * and writeJniCode() methods to finally emit the generated translation layer * (Java) and jni layer (C) code. *
* *

* Since the .defs data has already been demuxed into one .defs file per type, * we use the TypeBlock heading each file to identify it and to name the * appropriate output files. That setup, and the driving the passes over the * list of DefsFiles holding the Block arrays, is the task of this class, * which is the [only] public entry point into the code generator. * * @author Andrew Cowie * @since 4.0.3 */ /* * This class's name would seem to imply it is a subclass of Generator, which * of course is not the case. It is, however, a good name to have show up when * building the library via `make`, so "BindingsGenerator" it is. If someone * wants to suggest a better name, go ahead. */ public class BindingsGenerator { public static void main(String[] args) throws IOException { runGeneratorOutputToFiles(new File("src/defs/"), new File("generated/bindings/")); } /** * This is building towards the main loop that will drive the .defs file * parser and subsequent runs of the bindings code generators, but it is * still an intermediate form. */ private static void runGeneratorOutputToFiles(final File sourceDir, final File outputDir) { Block[] blocks; DefsParser parser; File[] files; DefsLineNumberReader in; DefsFile data; List all; Iterator iter; PrintWriter typeMapping; files = sourceDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { if (name.endsWith(".defs")) { return true; } else { return false; } } }); all = new ArrayList(files.length); /* * Load the all the .defs files into DefsFile objects, one per type. * Along the way, this registers the type information. */ for (int i = 0; i < files.length; i++) { try { in = new DefsLineNumberReader(new FileReader(files[i]), files[i].getName()); parser = new DefsParser(in); blocks = parser.parseData(); data = new DefsFile(blocks); all.add(data); in.close(); } catch (IOException ioe) { System.out.println("I/O problem when trying to parse " + files[i]); System.out.println(ioe.getMessage()); System.out.println("[continuing next file]\n"); continue; } catch (ImproperDefsFileException idfe) { System.out.println("Couldn't get sufficient information from " + files[i] + ":"); System.out.println(idfe.getMessage()); System.out.println("[continuing next file]\n"); continue; } finally { System.out.flush(); } } /* * Now, with the meta data completely loaded, we can generate the * bindings code. */ try { typeMapping = new PrintWriter(new BufferedWriter(new FileWriter( "generated/bindings/typeMapping.properties"))); } catch (IOException ie) { System.err.println("Can't open typeMapping file for writing!\n" + ie); return; } for (iter = all.iterator(); iter.hasNext();) { String packageAndClassName; File transTarget, jniTarget; PrintWriter trans, jni; data = iter.next(); packageAndClassName = data.getType().fullyQualifiedTranslationClassName().replace('.', '/'); transTarget = new File(outputDir, packageAndClassName + ".java"); jniTarget = new File(outputDir, packageAndClassName + ".c"); if (!transTarget.getParentFile().isDirectory()) { transTarget.getParentFile().mkdirs(); } try { trans = new PrintWriter(new BufferedWriter(new FileWriter(transTarget))); jni = new PrintWriter(new BufferedWriter(new FileWriter(jniTarget))); } catch (IOException ioe) { System.err.println("How come we can't open a file for writing?\n" + ioe); return; } try { data.generateTranslationLayer(trans); } catch (UnsupportedOperationException uoe) { // act to remove that file? Or close it off, or... } try { data.generateJniLayer(jni); } catch (UnsupportedOperationException uoe) { // act to remove the file in the event there was nothing // printed? } typeMapping.println(data.getType().bareTranslationClassName() + "=" + data.getType().fullyQualifiedJavaClassName()); trans.close(); jni.close(); } typeMapping.close(); } }