package processing.build; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; /** * Ant Task for copying the PImage and PGraphics methods into PApplet. */ public class PAppletMethods extends Task { private File baseDir; public PAppletMethods() { } public void setDir(String dir) { baseDir = new File(dir); } public void execute() throws BuildException { // Do a bunch of checks... if (baseDir == null) { throw new BuildException("dir parameter must be set!"); } File graphicsFile = new File(baseDir, "PGraphics.java"); File appletFile = new File(baseDir, "PApplet.java"); File imageFile = new File(baseDir, "PImage.java"); if (!graphicsFile.exists() || !graphicsFile.canRead()) { throw new BuildException("PGraphics file not readable: " + graphicsFile.getAbsolutePath()); } if (!appletFile.exists() || !appletFile.canRead() || !appletFile.canWrite()) { throw new BuildException("PApplet file not read/writeable: " + appletFile.getAbsolutePath()); } if (!imageFile.exists() || !imageFile.canRead()) { throw new BuildException("PImage file not readable: " + imageFile.getAbsolutePath()); } // Looking good, let's do this! ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); PrintStream out = new PrintStream(outBytes); StringBuffer content = new StringBuffer(); try{ BufferedReader applet = createReader(appletFile); String line; while ((line = applet.readLine()) != null) { out.println(line); content.append(line + "\n"); if (line.indexOf("public functions for processing.core") >= 0) { break; } } // read the rest of the file and append it to the while ((line = applet.readLine()) != null) { content.append(line + "\n"); } applet.close(); process(out, graphicsFile); process(out, imageFile); out.println("}"); } catch (IOException e) { e.printStackTrace(); } catch(Exception ex) { ex.printStackTrace(); } out.flush(); if (content.toString().equals(outBytes.toString())) { System.out.println("No changes to PApplet API."); } else { System.out.println("Updating PApplet with API changes from PImage or PGraphics."); try { PrintStream temp = new PrintStream(appletFile); temp.print(outBytes.toString()); temp.flush(); temp.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } } private void process(PrintStream out, File input) throws IOException { BufferedReader in = createReader(input); int comments = 0; String line = null; while ((line = in.readLine()) != null) { String decl = ""; // Keep track of comments if (line.matches(Pattern.quote("/*"))) { comments ++; } if (line.matches(Pattern.quote("*/"))) { comments --; } // Ignore everything inside comments if (comments > 0) { continue; } boolean gotSomething = false; boolean gotStatic = false; Matcher result; if ((result = Pattern.compile("^\\s*public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) { gotSomething = true; } else if ((result = Pattern.compile("^\\s*abstract public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) { gotSomething = true; } else if ((result = Pattern.compile("^\\s*public final ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) { gotSomething = true; } else if ((result = Pattern.compile("^\\s*static public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) { gotSomething = true; gotStatic = true; } // if function is marked "// ignore" then, uh, ignore it. if (gotSomething && line.indexOf("// ignore") >= 0) { gotSomething = false; } String returns = ""; if (gotSomething) { if (result.group(1).equals("void")) { returns = ""; } else { returns = "return "; } // remove the abstract modifier line = line.replaceFirst(Pattern.quote("abstract"), " "); // replace semicolons with a start def line = line.replaceAll(Pattern.quote(";"), " {\n"); out.println("\n\n" + line); decl += line; while(line.indexOf(')') == -1) { line = in.readLine(); decl += line; line = line.replaceAll("\\;\\s*$", " {\n"); out.println(line); } result = Pattern.compile(".*?\\s(\\S+)\\(.*?").matcher(decl); result.matches(); // try to match. DON't remove this or things will stop working! String declName = result.group(1); String gline = ""; String rline = ""; if (gotStatic) { gline = " " + returns + "PGraphics." + declName + "("; } else { rline = " if (recorder != null) recorder." + declName + "("; gline = " " + returns + "g." + declName + "("; } decl = decl.replaceAll("\\s+", " "); // smush onto a single line decl = decl.replaceFirst("^.*\\(", ""); decl = decl.replaceFirst("\\).*$", ""); int prev = 0; String parts[] = decl.split("\\, "); for (String part : parts) { if (!part.trim().equals("")) { String blargh[] = part.split(" "); String theArg = blargh[1].replaceAll("[\\[\\]]", ""); if (prev != 0) { gline += ", "; rline += ", "; } gline += theArg; rline += theArg; prev = 1; } } gline += ");"; rline += ");"; if (!gotStatic && returns.equals("")) { out.println(rline); } out.println(gline); out.println(" }"); } } in.close(); } private static BufferedReader createReader(File f) throws FileNotFoundException { return new BufferedReader(new InputStreamReader(new FileInputStream(f))); } }