1 // Copyright Mario Kröplin 2015. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module main; 7 8 import std.array; 9 import std.stdio; 10 11 int main(string[] args) 12 in (!args.empty) 13 { 14 import std.getopt : defaultGetoptPrinter, getopt, GetOptException, GetoptResult; 15 import std.path : baseName; 16 17 GetoptResult result; 18 try 19 { 20 result = getopt(args); 21 } 22 catch (GetOptException exception) 23 { 24 stderr.writeln("error: ", exception.msg); 25 return 1; 26 } 27 if (result.helpWanted) 28 { 29 writefln("Usage: %s [option...] file...", baseName(args[0])); 30 writeln("Reverse engineering of D source code into PlantUML classes."); 31 writeln("If no files are specified, input is read from stdin."); 32 defaultGetoptPrinter("Options:", result.options); 33 return 0; 34 } 35 return process(args[1 .. $]); 36 } 37 38 int process(string[] names) 39 { 40 import dparse.lexer : getTokensForParser, LexerConfig, StringBehavior, StringCache; 41 import dparse.parser : parseModule; 42 43 bool success = true; 44 StringCache cache = StringCache(StringCache.defaultBucketCount); 45 LexerConfig config; 46 config.stringBehavior = StringBehavior.source; 47 48 void outline(ubyte[] sourceCode, string name) 49 { 50 import dparse.rollback_allocator : RollbackAllocator; 51 import outliner : Outliner; 52 import std.typecons : scoped; 53 54 config.fileName = name; 55 auto tokens = getTokensForParser(sourceCode, config, &cache); 56 RollbackAllocator allocator; 57 auto module_ = parseModule(tokens, name, &allocator); 58 auto visitor = scoped!Outliner(stdout, name); 59 visitor.visit(module_); 60 } 61 62 if (names.empty) 63 outline(read(), "stdin"); 64 else 65 { 66 import std.file : FileException, read; 67 68 foreach (name; names) 69 { 70 try 71 { 72 outline(cast(ubyte[]) read(name), name); 73 } 74 catch (FileException exception) 75 { 76 stderr.writeln("error: ", exception.msg); 77 success = false; 78 } 79 } 80 } 81 return success ? 0 : 1; 82 } 83 84 ubyte[] read() 85 { 86 auto content = appender!(ubyte[])(); 87 ubyte[4096] buffer = void; 88 while (!stdin.eof) 89 { 90 auto slice = stdin.rawRead(buffer); 91 if (slice.empty) 92 break; 93 content.put(slice); 94 } 95 return content.data; 96 }