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 11 module rt.compiler.dmd.rt.dmain2; 12 13 private 14 { 15 import rt.compiler.util.console; 16 17 import tango.stdc.stdlib : malloc, free, exit, EXIT_FAILURE; 18 import tango.stdc.string : strlen; 19 } 20 21 version( Win32 ) 22 { 23 import tango.stdc.stdlib: alloca; 24 import tango.stdc.string: wcslen; 25 extern (Windows) void* LocalFree(void*); 26 extern (Windows) wchar* GetCommandLineW(); 27 extern (Windows) wchar** CommandLineToArgvW(wchar*, int*); 28 extern (Windows) export int WideCharToMultiByte(uint, uint, wchar*, int, char*, int, char*, int); 29 pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW 30 //pragma(lib, "tango-win32-dmd.lib"); // links Tango's Win32 library to reduce EXE size 31 } 32 33 extern (C) void _STI_monitor_staticctor(); 34 extern (C) void _STD_monitor_staticdtor(); 35 extern (C) void _STI_critical_init(); 36 extern (C) void _STD_critical_term(); 37 extern (C) void gc_init(); 38 extern (C) void gc_term(); 39 extern (C) void _minit(); 40 extern (C) void _moduleCtor(); 41 extern (C) void _moduleDtor(); 42 extern (C) void thread_joinAll(); 43 44 /*********************************** 45 * These functions must be defined for any D program linked 46 * against this library. 47 */ 48 extern (C) void onAssertError( char[] file, size_t line ); 49 extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg ); 50 extern (C) void onArrayBoundsError( char[] file, size_t line ); 51 extern (C) void onSwitchError( char[] file, size_t line ); 52 extern (C) bool runModuleUnitTests(); 53 54 // this function is called from the utf module 55 //extern (C) void onUnicodeError( char[] msg, size_t idx ); 56 57 /*********************************** 58 * These are internal callbacks for various language errors. 59 */ 60 extern (C) void _d_assert( char[] file, uint line ) 61 { 62 onAssertError( file, line ); 63 } 64 65 extern (C) static void _d_assert_msg( char[] msg, char[] file, uint line ) 66 { 67 onAssertErrorMsg( file, line, msg ); 68 } 69 70 extern (C) void _d_array_bounds( char[] file, uint line ) 71 { 72 onArrayBoundsError( file, line ); 73 } 74 75 extern (C) void _d_switch_error( char[] file, uint line ) 76 { 77 onSwitchError( file, line ); 78 } 79 80 bool _d_isHalting = false; 81 82 extern (C) bool rt_isHalting() 83 { 84 return _d_isHalting; 85 } 86 87 extern (C) bool rt_trapExceptions = true; 88 89 void _d_criticalInit() 90 { 91 static bool hasBeenCalled; 92 93 if (hasBeenCalled) 94 return; 95 96 hasBeenCalled = true; 97 98 version (Posix) 99 { 100 _STI_monitor_staticctor(); 101 _STI_critical_init(); 102 } 103 } 104 105 alias void delegate( Exception ) ExceptionHandler; 106 107 extern (C) bool rt_init( ExceptionHandler dg = null ) 108 { 109 static bool result; 110 111 if (result) 112 return result; 113 114 _d_criticalInit(); 115 116 try 117 { 118 gc_init(); 119 version (Win32) 120 _minit(); 121 _moduleCtor(); 122 return result = true; 123 } 124 catch( Exception e ) 125 { 126 if( dg ){ 127 dg( e ); 128 } else { 129 console("exception while executing module initializers:\n"); 130 e.writeOut(delegate void(char[]s){ 131 console(s); 132 }); 133 console(); 134 } 135 } 136 catch 137 { 138 console("error while executing module initializers\n"); 139 } 140 _d_criticalTerm(); 141 return result = false; 142 } 143 144 void _d_criticalTerm() 145 { 146 static bool hasBeenCalled; 147 148 if (hasBeenCalled) 149 return; 150 151 hasBeenCalled = true; 152 153 version (Posix) 154 { 155 _STD_critical_term(); 156 _STD_monitor_staticdtor(); 157 } 158 } 159 160 extern (C) bool rt_term( ExceptionHandler dg = null ) 161 { 162 static bool result; 163 164 if (result) 165 return result; 166 167 try 168 { 169 _d_isHalting = true; 170 thread_joinAll(); 171 _moduleDtor(); 172 gc_term(); 173 return result = true; 174 } 175 catch( Exception e ) 176 { 177 if( dg ) 178 dg( e ); 179 } 180 catch 181 { 182 183 } 184 finally 185 { 186 _d_criticalTerm(); 187 } 188 return result = false; 189 } 190 191 version (OSX) 192 { 193 // The bottom of the stack 194 extern (C) void* __osx_stack_end = cast(void*)0xC0000000; 195 } 196 197 version (FreeBSD) 198 { 199 // The bottom of the stack 200 extern (C) void* __libc_stack_end; 201 } 202 203 version (Solaris) 204 { 205 // The bottom of the stack 206 extern (C) void* __libc_stack_end; 207 } 208 209 /*********************************** 210 * The D main() function supplied by the user's program 211 */ 212 int main(char[][] args); 213 214 version(NoCMain) 215 { 216 217 } 218 else 219 { 220 221 /*********************************** 222 * Substitutes for the C main() function. 223 * It's purpose is to wrap the call to the D main() 224 * function and catch any unhandled exceptions. 225 */ 226 227 extern (C) int main(int argc, char **argv) 228 { 229 char[][] args; 230 int result; 231 232 version (OSX) 233 {/* OSX does not provide a way to get at the top of the 234 * stack, except for the magic value 0xC0000000. 235 * But as far as the gc is concerned, argv is at the top 236 * of the main thread's stack, so save the address of that. 237 */ 238 __osx_stack_end = cast(void*)&argv; 239 } 240 version (FreeBSD) 241 { /* FreeBSD does not provide a way to get at the top of the 242 * stack. 243 * But as far as the gc is concerned, argv is at the top 244 * of the main thread's stack, so save the address of that. 245 */ 246 __libc_stack_end = cast(void*)&argv; 247 } 248 249 version (Solaris) 250 { /* As far as the gc is concerned, argv is at the top 251 * of the main thread's stack, so save the address of that. 252 */ 253 __libc_stack_end = cast(void*)&argv; 254 } 255 256 version (Posix) 257 _d_criticalInit(); 258 259 version (Win32) 260 { 261 wchar* wcbuf = GetCommandLineW(); 262 size_t wclen = wcslen(wcbuf); 263 int wargc = 0; 264 wchar** wargs = CommandLineToArgvW(wcbuf, &wargc); 265 assert(wargc == argc); 266 267 char* cargp = null; 268 size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0); 269 270 cargp = cast(char*) alloca(cargl); 271 args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc]; 272 273 for (size_t i = 0, p = 0; i < wargc; i++) 274 { 275 int wlen = wcslen( wargs[i] ); 276 int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0); 277 args[i] = cargp[p .. p+clen]; 278 p += clen; assert(p <= cargl); 279 WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0); 280 } 281 LocalFree(wargs); 282 wargs = null; 283 wargc = 0; 284 } 285 else version (Posix) 286 { 287 char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof); 288 scope(exit) free(am); 289 290 for (size_t i = 0; i < argc; i++) 291 { 292 auto len = strlen(argv[i]); 293 am[i] = argv[i][0 .. len]; 294 } 295 args = am[0 .. argc]; 296 } 297 298 bool trapExceptions = rt_trapExceptions; 299 300 void tryExec(void delegate() dg) 301 { 302 303 if (trapExceptions) 304 { 305 try 306 { 307 dg(); 308 } 309 catch (Exception e) 310 { 311 e.writeOut(delegate void(char[]s){ console(s); }); 312 result = EXIT_FAILURE; 313 } 314 catch (Object o) 315 { 316 console (o.toString)("\n"); 317 result = EXIT_FAILURE; 318 } 319 } 320 else 321 { 322 dg(); 323 } 324 } 325 326 // NOTE: The lifetime of a process is much like the lifetime of an object: 327 // it is initialized, then used, then destroyed. If initialization 328 // fails, the successive two steps are never reached. However, if 329 // initialization succeeds, then cleanup will occur even if the use 330 // step fails in some way. Here, the use phase consists of running 331 // the user's main function. If main terminates with an exception, 332 // the exception is handled and then cleanup begins. An exception 333 // thrown during cleanup, however, will abort the cleanup process. 334 335 void runMain() 336 { 337 result = main(args); 338 } 339 340 void runAll() 341 { 342 rt_init(); 343 if (runModuleUnitTests()) 344 { 345 tryExec(&runMain); 346 } 347 348 rt_term(); 349 } 350 351 tryExec(&runAll); 352 353 version (Posix) 354 _d_criticalTerm(); 355 356 return result; 357 } 358 359 }