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