1 /*
2  * Placed into the Public Domain.
3  * written by Walter Bright
4  * www.digitalmars.com
5  */
6 
7 /*
8  *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
9  */
10 module rt.dmain2;
11 
12 private
13 {
14     import rt.compiler.util.console;
15     import tango.stdc.stdlib : malloc, free, exit, EXIT_FAILURE;
16     import tango.stdc.string : strlen;
17     import tango.stdc.stdio : printf;
18     import rt.memory;
19 }
20 
21 version( Win32 )
22 {
23     import tango.stdc.stdlib: wchar_t, alloca;
24     import tango.stdc.string: wcslen;
25     import tango.sys.win32.UserGdi: LocalFree,GetCommandLineW,CommandLineToArgvW,WideCharToMultiByte;
26     //pragma(lib, "shell32.lib");   // needed for CommandLineToArgvW
27     //pragma(lib, "tango-win32-dmd.lib"); // links Tango's Win32 library to reduce EXE size
28 }
29 
30 extern (C) void _STI_monitor_staticctor();
31 extern (C) void _STD_monitor_staticdtor();
32 extern (C) void _STI_critical_init();
33 extern (C) void _STD_critical_term();
34 extern (C) void gc_init();
35 extern (C) void gc_term();
36 extern (C) void _moduleCtor();
37 extern (C) void _moduleDtor();
38 extern (C) void thread_joinAll();
39 
40 //debug=PRINTF;
41 
42 /***********************************
43  * These functions must be defined for any D program linked
44  * against this library.
45  */
46 extern (C) void onAssertError( char[] file, size_t line );
47 extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg );
48 extern (C) void onArrayBoundsError( char[] file, size_t line );
49 extern (C) void onSwitchError( char[] file, size_t line );
50 extern (C) bool runModuleUnitTests();
51 
52 // this function is called from the utf module
53 //extern (C) void onUnicodeError( char[] msg, size_t idx );
54 
55 /***********************************
56  * These are internal callbacks for various language errors.
57  */
58 extern (C) void _d_assert( char[] file, uint line )
59 {
60     onAssertError( file, line );
61 }
62 
63 extern (C) void _d_assert_msg( char[] msg, char[] file, uint line )
64 {
65     onAssertErrorMsg( file, line, msg );
66 }
67 
68 extern (C) void _d_array_bounds( char[] file, uint line )
69 {
70     onArrayBoundsError( file, line );
71 }
72 
73 extern (C) void _d_switch_error( char[] file, uint line )
74 {
75     onSwitchError( file, line );
76 }
77 
78 bool _d_isHalting = false;
79 
80 extern (C) bool rt_isHalting()
81 {
82     return _d_isHalting;
83 }
84 
85 extern (C) bool rt_trapExceptions = true;
86 
87 void _d_criticalInit()
88 {
89     _STI_monitor_staticctor();
90     _STI_critical_init();
91     initStaticDataPtrs();
92 }
93 
94 alias void delegate( Exception ) ExceptionHandler;
95 
96 // this is here so users can manually initialize the runtime
97 // for example, when there is no main function etc.
98 extern (C) bool rt_init( ExceptionHandler dg = null )
99 {
100     _d_criticalInit();
101 
102     try
103     {
104         gc_init();
105         _moduleCtor();
106         return true;
107     }
108     catch( Exception e )
109     {
110         if( dg ){
111             dg( e );
112         } else {
113             console("exception while executing module initializers:\n");
114             e.writeOut(delegate void(char[]s){
115                 console(s);
116             });
117             console();
118         }
119     }
120     catch
121     {
122         console("error while executing module initializers\n");
123     }
124     _d_criticalTerm();
125     return false;
126 }
127 
128 void _d_criticalTerm()
129 {
130     _STD_critical_term();
131     _STD_monitor_staticdtor();
132 }
133 
134 // this is here so users can manually terminate the runtime
135 // for example, when there is no main function etc.
136 extern (C) bool rt_term( ExceptionHandler dg = null )
137 {
138     try
139     {
140         thread_joinAll();
141         _d_isHalting = true;
142         _moduleDtor();
143         gc_term();
144         return true;
145     }
146     catch( Exception e )
147     {
148         if( dg )
149             dg( e );
150     }
151     catch
152     {
153 
154     }
155     finally
156     {
157         _d_criticalTerm();
158     }
159     return false;
160 }
161 
162 /***********************************
163  * The D main() function supplied by the user's program
164  */
165 int main(char[][] args);
166 
167 version(NoCMain)
168 {
169 	
170 }
171 else
172 {
173 
174 /***********************************
175  * Substitutes for the C main() function.
176  * It's purpose is to wrap the call to the D main()
177  * function and catch any unhandled exceptions.
178  */
179 
180 extern (C) int main(int argc, char **argv, char** env)
181 {
182     char[][] args;
183     int result;
184 
185     debug(PRINTF) printf("main ctors\n");
186     _STI_monitor_staticctor();
187     _STI_critical_init();
188     initStaticDataPtrs();
189 
190     debug(PRINTF) printf("main args\n");
191     // GDC seems to get by without this Windows special case...
192     version (Win32)
193     {
194         wchar_t*  wcbuf = GetCommandLineW();
195         size_t    wclen = wcslen(wcbuf);
196         int       wargc = 0;
197         wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
198         assert(wargc == argc);
199 
200         char*     cargp = null;
201         size_t    cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, null);
202 
203         cargp = cast(char*) alloca(cargl);
204         args  = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
205 
206         for (size_t i = 0, p = 0; i < wargc; i++)
207         {
208             int wlen = wcslen( wargs[i] );
209             int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, null);
210             args[i]  = cargp[p .. p+clen];
211             p += clen; assert(p <= cargl);
212             WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, null);
213         }
214         LocalFree(wargs);
215         wargs = null;
216         wargc = 0;
217     }
218     else
219     {
220         char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
221         scope(exit) free(am);
222 
223         for (size_t i = 0; i < argc; i++)
224         {
225             auto len = strlen(argv[i]);
226             am[i] = argv[i][0 .. len];
227         }
228         args = am[0 .. argc];
229     }
230 
231     debug(PRINTF) printf("main trap exceptions\n");
232     bool trapExceptions = rt_trapExceptions;
233 
234     void tryExec(void delegate() dg)
235     {
236         debug(PRINTF) printf("main try exec\n");
237         if (trapExceptions)
238         {
239             try
240             {
241                 dg();
242             }
243             catch (Exception e)
244             {
245                 e.writeOut(delegate void(char[]s){ console(s); });
246                 result = EXIT_FAILURE;
247             }
248             catch (Object o)
249             {
250                 // fprintf(stderr, "%.*s\n", o.toString());
251                 console (o.toString)("\n");
252                 result = EXIT_FAILURE;
253             }
254         }
255         else
256         {
257             dg();
258         }
259     }
260 
261     // NOTE: The lifetime of a process is much like the lifetime of an object:
262     //       it is initialized, then used, then destroyed.  If initialization
263     //       fails, the successive two steps are never reached.  However, if
264     //       initialization succeeds, then cleanup will occur even if the use
265     //       step fails in some way.  Here, the use phase consists of running
266     //       the user's main function.  If main terminates with an exception,
267     //       the exception is handled and then cleanup begins.  An exception
268     //       thrown during cleanup, however, will abort the cleanup process.
269 
270     void runMain()
271     {
272         debug(PRINTF) printf("main runMain\n");
273         result = main(args);
274     }
275 
276     void runAll()
277     {
278         debug(PRINTF) printf("main runAll\n");
279         gc_init();
280         _moduleCtor();
281         if (runModuleUnitTests())
282             tryExec(&runMain);
283         _d_isHalting = true;
284         thread_joinAll();
285         _moduleDtor();
286         gc_term();
287     }
288 
289     tryExec(&runAll);
290 
291     debug(PRINTF) printf("main dtor\n");
292     _STD_critical_term();
293     _STD_monitor_staticdtor();
294 
295     return result;
296 }
297 
298 }