1 // Scriptlike: Utility to aid in script-like programs. 2 // Written in the D programming language. 3 4 module scriptlike.fail; 5 6 import std.file; 7 import std.path; 8 import std.traits; 9 10 // Throwable.toString(sink) isn't an override on DMD 2.064.2, and druntime 11 // won't even call any Throwable.toString on DMD 2.064.2 anyway, so use 12 // a fallback method if Throwable doesn't have toString(sink). 13 static if( MemberFunctionsTuple!(Throwable, "toString").length > 1 ) 14 enum useFallback = false; 15 else 16 enum useFallback = true; 17 18 /// This is the exception thrown by fail(). There's no need to create or throw 19 /// this directly, but it's public in case you have reason to catch it. 20 class Fail : Exception 21 { 22 private this() 23 { 24 super(null); 25 } 26 27 private static string msg; 28 private static Fail opCall(string msg, string file=__FILE__, int line=__LINE__) 29 { 30 Fail.msg = msg; 31 throw cast(Fail) cast(void*) Fail.classinfo.init; 32 } 33 34 private static string fullMessage(string msg = Fail.msg) 35 { 36 auto appName = thisExePath().baseName(); 37 38 version(Windows) 39 appName = appName.stripExtension(); 40 41 return appName~": ERROR: "~msg; 42 } 43 44 static if(!useFallback) 45 { 46 override void toString(scope void delegate(in char[]) sink) const 47 { 48 sink(fullMessage()); 49 } 50 } 51 } 52 53 /++ 54 Call this to end your program with an error message for the user, and no 55 ugly stack trace. The error message is sent to stderr and the errorlevel is 56 set to non-zero. 57 58 This is exception-safe, all cleanup code gets run. 59 60 Your program's name is automatically detected from std.file.thisExePath. 61 62 Note, on DMD 2.064.2, the error message is displayed BEFORE the exception is 63 thrown. So if you catch the Fail exception, the message will have already been 64 displayed. This is due to limitations in the older druntime, and is fixed 65 on DMD 2.065 and up. 66 67 Example: 68 ---------------- 69 fail("You forgot to provide a destination!"); 70 71 // Output on DMD 2.065 and up: 72 // yourProgramName: ERROR: You forgot to provide a destination! 73 74 // Output on DMD 2.064.2: 75 // yourProgramName: ERROR: You forgot to provide a destination! 76 // scriptlike.fail.Fail 77 ---------------- 78 +/ 79 void fail(string msg) 80 { 81 static if(useFallback) 82 { 83 import std.stdio; 84 stderr.writeln(Fail.fullMessage(msg)); 85 stderr.flush(); 86 } 87 88 throw Fail(msg); 89 } 90