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
13 {
14     assert(!args.empty);
15 }
16 body
17 {
18     import std.getopt : defaultGetoptPrinter, getopt, GetOptException, GetoptResult;
19     import std.path : baseName;
20 
21     GetoptResult result;
22     try
23     {
24         result = getopt(args);
25     }
26     catch (GetOptException exception)
27     {
28         stderr.writeln("error: ", exception.msg);
29         return 1;
30     }
31     if (result.helpWanted)
32     {
33         writefln("Usage: %s [option...] file...", baseName(args[0]));
34         writeln("Reverse engineering of D source code into PlantUML classes.");
35         writeln("If no files are specified, input is read from stdin.");
36         defaultGetoptPrinter("Options:", result.options);
37         return 0;
38     }
39     return process(args[1 .. $]);
40 }
41 
42 int process(string[] names)
43 {
44     import dparse.lexer : getTokensForParser, LexerConfig, StringBehavior, StringCache;
45     import dparse.parser : parseModule;
46 
47     bool success = true;
48     StringCache cache = StringCache(StringCache.defaultBucketCount);
49     LexerConfig config;
50     config.stringBehavior = StringBehavior.source;
51 
52     void outline(ubyte[] sourceCode, string name)
53     {
54         import dparse.rollback_allocator : RollbackAllocator;
55         import outliner : Outliner;
56         import std.typecons : scoped;
57 
58         config.fileName = name;
59         auto tokens = getTokensForParser(sourceCode, config, &cache);
60         RollbackAllocator allocator;
61         auto module_ = parseModule(tokens, name, &allocator);
62         auto visitor = scoped!Outliner(stdout, name);
63         visitor.visit(module_);
64     }
65 
66     if (names.empty)
67         outline(read(), "stdin");
68     else
69     {
70         import std.file : FileException, read;
71 
72         foreach (name; names)
73         {
74             try
75             {
76                 outline(cast(ubyte[]) read(name), name);
77             }
78             catch (FileException exception)
79             {
80                 stderr.writeln("error: ", exception.msg);
81                 success = false;
82             }
83         }
84     }
85     return success ? 0 : 1;
86 }
87 
88 ubyte[] read()
89 {
90     auto content = appender!(ubyte[])();
91     ubyte[4096] buffer = void;
92     while (!stdin.eof)
93     {
94         auto slice = stdin.rawRead(buffer);
95         if (slice.empty)
96             break;
97         content.put(slice);
98     }
99     return content.data;
100 }