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 }