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 }