1 module exitclean;
2 class ExitException : Exception
3 {
4     int code;
5     string funcName;
6 
7     this(int code, string msg = null,
8         string file = __FILE__, size_t line = __LINE__,
9         string funcName = __PRETTY_FUNCTION__)
10     {
11         this.code = code;
12         this.funcName = funcName;
13         super(msg, file, line);
14     }
15 }
16 
17 private ubyte[__traits(classInstanceSize, ExitException)] exitExceptionBuffer;
18 
19 void exit(int code, string msg = null,
20     string file = __FILE__, size_t line = __LINE__,
21     string funcName = __PRETTY_FUNCTION__)
22 {
23     if (exitExceptionBuffer != typeof(exitExceptionBuffer).init)
24         assert(0); //no support for chaining ExitExceptions
25     import std.conv : emplace;
26     throw emplace!ExitException(exitExceptionBuffer,
27         code, msg, file, line, funcName);
28 }
29 
30 debug version = ShowExitLoc;
31 version (ShowExitTrace) version = ShowExitLoc;
32 
33 mixin template Main(alias codeMain)
34 {
35     int main(string[] args)
36     {
37         import std.meta : AliasSeq;
38         import std.traits : Parameters, ReturnType;
39         static if (is(Parameters!codeMain[0] == string[]))
40             alias codeMainArgs = args;
41         else
42             alias codeMainArgs = AliasSeq!();
43 
44         try {
45             static if (is(ReturnType!codeMain == int))
46                 return codeMain(codeMainArgs);
47             else
48             {
49                 codeMain(codeMainArgs);
50                 return 0;
51             }
52         }
53         catch (ExitException e)
54         {
55             version (ShowExitLoc)
56             {
57                 import std.stdio : stderr;
58                 stderr.writeln("Exitting from ", e.funcName,
59                     " @ ", e.file, "(", e.line, ") with message: \"", e.msg, "\"");
60             }
61             version (ShowExitTrace)
62                 if (e.info)
63                     foreach(t; e.info)
64                         stderr.writeln(t);
65             return e.code;
66         }
67     }
68 }