1 /**
2  * A sensible main() function.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.utils.main;
15 
16 /**
17  * Mix in a main function, which should be adequate
18  * for most end-user programs.
19  *
20  * In debug mode (-debug), this is a pass-through.
21  * Otherwise, this will catch uncaught exceptions,
22  * and display only the message (sans stack trace)
23  * to the user - on standard error, or, for Windows
24  * GUI programs, in a message box.
25  */
26 mixin template main(alias realMain)
27 {
28 	version (unittest_only)
29 	{
30 		shared static this()
31 		{
32 			import core.runtime : Runtime, UnitTestResult;
33 			Runtime.extendedModuleUnitTester = {
34 				foreach (m; ModuleInfo)
35 					if (m)
36 						if (auto fp = m.unitTest)
37 							fp();
38 				return UnitTestResult();
39 			};
40 		}
41 	}
42 	else
43 	int main(string[] args)
44 	{
45 		int run(string[] args)
46 		{
47 			static if (is(typeof(realMain())))
48 				static if (is(typeof(realMain()) == void))
49 					{ realMain(); return 0; }
50 				else
51 					return realMain();
52 			else
53 				static if (is(typeof(realMain(args)) == void))
54 					{ realMain(args); return 0; }
55 				else
56 					return realMain(args);
57 		}
58 
59 		int runCatchingException(E, string message)(string[] args)
60 		{
61 			try
62 				return run(args);
63 			catch (E e)
64 			{
65 				version (Windows)
66 				{
67 					import core.sys.windows.windows;
68 					auto h = GetStdHandle(STD_ERROR_HANDLE);
69 					if (!h || h == INVALID_HANDLE_VALUE)
70 					{
71 						import ae.sys.windows : messageBox;
72 						messageBox(e.msg, message, MB_ICONERROR);
73 						return 1;
74 					}
75 				}
76 
77 				import std.stdio : stderr;
78 				stderr.writefln("%s: %s", message, e.msg);
79 				return 1;
80 			}
81 		}
82 
83 		debug
84 			static if(is(std.getopt.GetOptException))
85 				return runCatchingException!(std.getopt.GetOptException, "Usage error")(args);
86 			else
87 				return run(args);
88 		else
89 			return runCatchingException!(Throwable, "Fatal error")(args);
90 	}
91 }