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 }