diff --git a/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java b/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java index e25d57c..462d2da 100644 --- a/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java +++ b/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java @@ -670,6 +670,7 @@ public class ClassAnalyzer dumpSource(writer, pl, 0.8, 0.2); if (pl != null) pl.updateProgress(1.0, name); + writer.close(); } public boolean isScopeOf(Object obj, int scopeType) { diff --git a/jode/src/net/sf/jode/decompiler/Main.java b/jode/src/net/sf/jode/decompiler/Main.java index bd5c4e9..385476f 100644 --- a/jode/src/net/sf/jode/decompiler/Main.java +++ b/jode/src/net/sf/jode/decompiler/Main.java @@ -53,6 +53,7 @@ public class Main extends Options { new LongOpt("debug", LongOpt.OPTIONAL_ARGUMENT, null, 'D'), new LongOpt("import", LongOpt.REQUIRED_ARGUMENT, null, 'i'), new LongOpt("style", LongOpt.REQUIRED_ARGUMENT, null, 's'), + new LongOpt("chars-per-line", LongOpt.REQUIRED_ARGUMENT, null, 'l'), new LongOpt("lvt", LongOpt.OPTIONAL_ARGUMENT, null, OPTION_START+0), new LongOpt("inner", LongOpt.OPTIONAL_ARGUMENT, null, @@ -94,8 +95,10 @@ public class Main extends Options { "The directories should be separated by ','."); err.println(" -d, --dest "+ "write decompiled files to disk into directory destdir."); - err.println(" -s, --style {sun|gnu} "+ + err.println(" -s, --style {sun|gnu|pascal|python} "+ "specify indentation style"); + err.println(" -l, --chars-per-line "+ + "specify line length"); err.println(" -i, --import ,"); err.println(" "+ "import classes used more than clslimit times"); @@ -250,12 +253,13 @@ public class Main extends Options { int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;; int outputStyle = TabbedPrintWriter.BRACE_AT_EOL; int indentSize = 4; + int outputLineLength = 79; boolean keepGoing = false; GlobalOptions.err.println(GlobalOptions.copyright); boolean errorInParams = false; - Getopt g = new Getopt("net.sf.jode.decompiler.Main", params, "hVvkc:d:D:i:s:", + Getopt g = new Getopt("net.sf.jode.decompiler.Main", params, "hVvkc:d:D:i:s:l:", longOptions, true); for (int opt = g.getopt(); opt != -1; opt = g.getopt()) { switch(opt) { @@ -309,9 +313,12 @@ public class Main extends Options { } else if (arg.equals("sun")) { outputStyle = TabbedPrintWriter.BRACE_AT_EOL; indentSize = 4; - } else if (arg.equals("pascal")) { - outputStyle = 0; - indentSize = 4; + } else if (arg.equals("pascal")) { + outputStyle = 0; + indentSize = 4; + } else if (arg.equals("python") || arg.equals("codd")) { + outputStyle = TabbedPrintWriter.BRACE_AT_EOL|TabbedPrintWriter.CODD_FORMATTING; + indentSize = 4; } else { GlobalOptions.err.println ("net.sf.jode.decompiler.Main: Unknown style `"+arg+"'."); @@ -319,6 +326,18 @@ public class Main extends Options { } break; } + case 'l': { + String arg = g.getOptarg(); + try { + outputLineLength = Integer.parseInt(arg.trim()); + } + catch (RuntimeException rte) { + GlobalOptions.err.println( + "net.sf.jode.decompiler.Main: Invalid Linelength " + arg); + errorInParams = true; + } + break; + } case 'i': { String arg = g.getOptarg(); int comma = arg.indexOf(','); @@ -365,7 +384,7 @@ public class Main extends Options { TabbedPrintWriter writer = null; if (destDir == null) writer = new TabbedPrintWriter(System.out, imports, true, - outputStyle, indentSize, 0, 79); + outputStyle, indentSize, 0, outputLineLength); else if (destDir.toLowerCase().endsWith(".zip") || destDir.toLowerCase().endsWith(".jar")) { try { @@ -377,7 +396,7 @@ public class Main extends Options { } writer = new TabbedPrintWriter(new BufferedOutputStream(destZip), imports, false, - outputStyle, indentSize, 0, 79); + outputStyle, indentSize, 0, outputLineLength); } for (int i= g.getOptind(); i< params.length; i++) { try { diff --git a/jode/src/net/sf/jode/decompiler/TabbedPrintWriter.java b/jode/src/net/sf/jode/decompiler/TabbedPrintWriter.java index 2be7843..89cd974 100644 --- a/jode/src/net/sf/jode/decompiler/TabbedPrintWriter.java +++ b/jode/src/net/sf/jode/decompiler/TabbedPrintWriter.java @@ -42,6 +42,7 @@ public class TabbedPrintWriter { public static final int BRACE_AT_EOL = 0x10; public static final int INDENT_BRACES = 0x20; public static final int GNU_SPACING = 0x40; + public static final int CODD_FORMATTING = 0x80; // allow trailing CLOSING braces as well /** * This string contains a few tab characters followed by tabWidth - 1 @@ -72,19 +73,18 @@ public class TabbedPrintWriter { indent -= tabs * tabWidth; if (tabs <= FASTINDENT) { /* The fast way. */ - return tabSpaceString.substring(FASTINDENT - tabs, + return tabSpaceString.substring(FASTINDENT - tabs, FASTINDENT + indent); - } else { - /* the not so fast way */ - StringBuffer sb = new StringBuffer(tabs + indent); - while (tabs > FASTINDENT) { - sb.append(tabSpaceString.substring(0, FASTINDENT)); - tabs -= 20; - } - sb.append(tabSpaceString.substring(FASTINDENT - tabs, - FASTINDENT + indent)); - return sb.toString(); - } + } + /* the not so fast way */ + StringBuffer sb = new StringBuffer(tabs + indent); + while (tabs > FASTINDENT) { + sb.append(tabSpaceString.substring(0, FASTINDENT)); + tabs -= 20; + } + sb.append(tabSpaceString.substring(FASTINDENT - tabs, + FASTINDENT + indent)); + return sb.toString(); } class BreakPoint { @@ -460,7 +460,10 @@ public class TabbedPrintWriter { public TabbedPrintWriter (OutputStream os, ImportHandler imports, boolean autoFlush, int style, int indentSize, int tabWidth, int lineWidth) { - pw = new PrintWriter(os, autoFlush); + if ((style & CODD_FORMATTING) != 0) + pw = new PrintWriter(new NlRemover(new OutputStreamWriter(os), tabWidth), autoFlush); + else + pw = new PrintWriter(os, autoFlush); this.imports = imports; this.style = style; this.indentsize = indentSize; @@ -469,10 +472,11 @@ public class TabbedPrintWriter { init(); } - public TabbedPrintWriter (Writer os, ImportHandler imports, - boolean autoFlush, int style, - int indentSize, int tabWidth, int lineWidth) { - pw = new PrintWriter(os, autoFlush); + public TabbedPrintWriter (Writer os, ImportHandler imports, boolean autoFlush, int style, int indentSize, int tabWidth, int lineWidth) { + if ((style & CODD_FORMATTING) != 0) + pw = new PrintWriter(new NlRemover(os, tabWidth), autoFlush); + else { + pw = new PrintWriter(os, autoFlush); } this.imports = imports; this.style = style; this.indentsize = indentSize; @@ -492,19 +496,19 @@ public class TabbedPrintWriter { } public TabbedPrintWriter (OutputStream os, ImportHandler imports) { - this(os, imports, true, BRACE_AT_EOL, 4, 8, 79); + this(os, imports, true); } public TabbedPrintWriter (Writer os, ImportHandler imports) { - this(os, imports, true, BRACE_AT_EOL, 4, 8, 79); + this(os, imports, true); } public TabbedPrintWriter (OutputStream os) { - this(os, null, true, BRACE_AT_EOL, 4, 8, 79); + this(os, null); } public TabbedPrintWriter (Writer os) { - this(os, null, true, BRACE_AT_EOL, 4, 8, 79); + this(os, null); } private void init() { @@ -516,7 +520,7 @@ public class TabbedPrintWriter { private void initTabString() { char tabChar = '\t'; - if (tabWidth == 0) { + if (tabWidth <= 1) { /* If tabWidth is 0 use spaces instead of tabs. */ tabWidth = 1; tabChar = ' '; @@ -690,8 +694,7 @@ public class TabbedPrintWriter { if (scope != null) return "NAME CONFLICT " + className; - else - return "UNREACHABLE " + className; + return "UNREACHABLE " + className; } if (imports != null) { String importedName = imports.getClassString(clazz); @@ -791,7 +794,7 @@ public class TabbedPrintWriter { } public void closeBraceContinue() { - if ((style & BRACE_AT_EOL) != 0) + if ((style & (BRACE_AT_EOL|CODD_FORMATTING)) == BRACE_AT_EOL) print("} "); else println("}"); @@ -823,3 +826,79 @@ public class TabbedPrintWriter { pw.close(); } } + + +class NlRemover extends Writer { + private int tabWidth; + private Writer out; + private int pendingNL; + private boolean lastWasClBr; + private int pendingSpace; + + public NlRemover(Writer to, int tabWidth) { + this.out = to; + this.tabWidth = tabWidth; } + + public void close() throws IOException { + if (out != null) { + while (pendingNL > 0) { + out.write('\n'); + pendingNL--; + } + out.close(); + out = null; + } + } + + public void flush() throws IOException { + if (out != null) + out.flush(); + } + + public void write(int x) throws IOException { + switch ((char)x) { + + case '}': + if (! lastWasClBr && pendingSpace > 0) + out.write(' '); + out.write('}'); + pendingSpace = 0; + pendingNL = 0; + lastWasClBr = true; + return; + case '\r': + pendingSpace = 0; + return; + case '\n': + if (pendingNL > 0) { + out.write('\n'); } + else + pendingNL++; + pendingSpace = 0; + return; + case '\t': + pendingSpace = (pendingSpace + tabWidth) / tabWidth * tabWidth; + return; + case ' ': + pendingSpace += 1; + return; + default: + while (pendingNL > 0) { + out.write('\n'); + pendingNL--; + } + while (pendingSpace > 0) { + out.write(' '); + pendingSpace--; + } + out.write(x); + lastWasClBr = false; + } + } + + public void write(char[] cbuf, int off, int len) throws IOException { + len+=off; + while (off < len) + write(cbuf[off++]); + } +}