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 	int main(string[] args)
29 	{
30 		int run(string[] args)
31 		{
32 			static if (is(typeof(realMain())))
33 				static if (is(typeof(realMain()) == void))
34 					{ realMain(); return 0; }
35 				else
36 					return realMain();
37 			else
38 				static if (is(typeof(realMain(args)) == void))
39 					{ realMain(args); return 0; }
40 				else
41 					return realMain(args);
42 		}
43 
44 		int runCatchingException(E, string message)(string[] args)
45 		{
46 			try
47 				return run(args);
48 			catch (E e)
49 			{
50 				version (Windows)
51 				{
52 					import core.sys.windows.windows;
53 					auto h = GetStdHandle(STD_ERROR_HANDLE);
54 					if (!h || h == INVALID_HANDLE_VALUE)
55 					{
56 						import ae.sys.windows : messageBox;
57 						messageBox(e.msg, message, MB_ICONERROR);
58 						return 1;
59 					}
60 				}
61 
62 				import std.stdio : stderr;
63 				stderr.writefln("%s: %s", message, e.msg);
64 				return 1;
65 			}
66 		}
67 
68 		debug
69 			static if(is(std.getopt.GetOptException))
70 				return runCatchingException!(std.getopt.GetOptException, "Usage error")(args);
71 			else
72 				return run(args);
73 		else
74 			return runCatchingException!(Throwable, "Fatal error")(args);
75 	}
76 }