revert optimization in change#4700 (it appears OPpRUNTIME flag
[p5sagit/p5-mst-13.2.git] / win32 / gstartup.c
1 /*
2  * gstartup.c
3  *
4  * Startup file for GCC/Mingw32 builds
5  * (replaces gcc's default c:\egcs\...\{crt1.o,dllcrt1.o})
6  *
7  * This file is taken from the Mingw32 package.
8  *  Created by Colin Peters for Mingw32
9  *  Modified by Mumit Khan
10  *
11  * History with Perl:
12  *  Added (in modified form) to Perl standard distribution to fix
13  *    problems linking against PerlCRT or MSVCRT
14  *    -- Benjamin Stuhl <sho_pi@hotmail.com> 10-17-1999
15 */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <io.h>
20 #include <fcntl.h>
21 #include <process.h>
22 #include <float.h>
23 #include <windows.h>
24 #include <signal.h>
25
26 /*
27  * Access to a standard 'main'-like argument count and list. Also included
28  * is a table of environment variables.
29  */
30 int _argc;
31 char **_argv;
32
33 extern int _CRT_glob;
34
35 #ifdef __MSVCRT__
36 typedef struct {
37   int newmode;
38 } _startupinfo;
39 extern void __getmainargs (int *, char ***, char ***, int, _startupinfo *);
40 #else
41 extern void __GetMainArgs (int *, char ***, char ***, int);
42 #endif
43
44 /*
45  * Initialize the _argc, _argv and environ variables.
46  */
47 static void
48 _mingw32_init_mainargs ()
49 {
50   /* The environ variable is provided directly in stdlib.h through
51    * a dll function call. */
52   char **dummy_environ;
53 #ifdef __MSVCRT__
54   _startupinfo start_info;
55   start_info.newmode = 0;
56 #endif
57
58   /*
59    * Microsoft's runtime provides a function for doing just that.
60    */
61 #ifdef __MSVCRT__
62   (void) __getmainargs (&_argc, &_argv, &dummy_environ, _CRT_glob, 
63                         &start_info);
64 #else
65   /* CRTDLL version */
66   (void) __GetMainArgs (&_argc, &_argv, &dummy_environ, _CRT_glob);
67 #endif
68 }
69
70 #if defined(EXESTARTUP) /* gcrt0.o - startup for an executable */
71
72 extern int main (int, char **, char **);
73
74 /*
75  * Must have the correct app type for MSVCRT. 
76  */
77
78 #ifdef __MSVCRT__
79 #define __UNKNOWN_APP    0
80 #define __CONSOLE_APP    1
81 #define __GUI_APP        2
82 __MINGW_IMPORT void __set_app_type(int);
83 #endif /* __MSVCRT__ */
84
85 /*
86  * Setup the default file handles to have the _CRT_fmode mode, as well as
87  * any new files created by the user.
88  */
89 extern unsigned int _CRT_fmode;
90
91 static void
92 _mingw32_init_fmode ()
93 {
94   /* Don't set the file mode if the user hasn't set any value for it. */
95   if (_CRT_fmode)
96     {
97       _fmode = _CRT_fmode;
98
99       /*
100        * This overrides the default file mode settings for stdin,
101        * stdout and stderr. At first I thought you would have to
102        * test with isatty, but it seems that the DOS console at
103        * least is smart enough to handle _O_BINARY stdout and
104        * still display correctly.
105        */
106       if (stdin)
107         {
108           _setmode (_fileno (stdin), _CRT_fmode);
109         }
110       if (stdout)
111         {
112           _setmode (_fileno (stdout), _CRT_fmode);
113         }
114       if (stderr)
115         {
116           _setmode (_fileno (stderr), _CRT_fmode);
117         }
118     }
119 }
120
121 /* This function will be called when a trap occurs. Thanks to Jacob
122    Navia for his contribution. */
123 static CALLBACK long
124 _gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
125 {
126   void (*old_handler) (int);
127   long action = EXCEPTION_CONTINUE_SEARCH;
128   int reset_fpu = 0;
129
130   switch (exception_data->ExceptionRecord->ExceptionCode)
131     {
132     case EXCEPTION_ACCESS_VIOLATION:
133       /* test if the user has set SIGSEGV */
134       old_handler = signal (SIGSEGV, SIG_DFL);
135       if (old_handler == SIG_IGN)
136         {
137           /* this is undefined if the signal was raised by anything other
138              than raise ().  */
139           signal (SIGSEGV, SIG_IGN);
140           action = EXCEPTION_CONTINUE_EXECUTION;
141         }
142       else if (old_handler != SIG_DFL)
143         {
144           /* This means 'old' is a user defined function. Call it */
145           (*old_handler) (SIGSEGV);
146           action = EXCEPTION_CONTINUE_EXECUTION;
147         }
148       break;
149
150     case EXCEPTION_FLT_INVALID_OPERATION:
151     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
152     case EXCEPTION_FLT_DENORMAL_OPERAND:
153     case EXCEPTION_FLT_OVERFLOW:
154     case EXCEPTION_FLT_UNDERFLOW:
155     case EXCEPTION_FLT_INEXACT_RESULT:
156       reset_fpu = 1;
157       /* fall through. */
158
159     case EXCEPTION_INT_DIVIDE_BY_ZERO:
160       /* test if the user has set SIGFPE */
161       old_handler = signal (SIGFPE, SIG_DFL);
162       if (old_handler == SIG_IGN)
163         {
164           signal (SIGFPE, SIG_IGN);
165           if (reset_fpu)
166             _fpreset ();
167           action = EXCEPTION_CONTINUE_EXECUTION;
168         }
169       else if (old_handler != SIG_DFL)
170         {
171           /* This means 'old' is a user defined function. Call it */
172           (*old_handler) (SIGFPE);
173           action = EXCEPTION_CONTINUE_EXECUTION;
174         }
175       break;
176
177     default:
178       break;
179     }
180   return action;
181 }
182
183 /*
184  * The function mainCRTStartup is the entry point for all console programs.
185  */
186 static int
187 __mingw_CRTStartup ()
188 {
189   int nRet;
190
191   /*
192    * Set up the top-level exception handler so that signal handling
193    * works as expected. The mapping between ANSI/POSIX signals and
194    * Win32 SE is not 1-to-1, so caveat emptore.
195    * 
196    */
197   SetUnhandledExceptionFilter (_gnu_exception_handler);
198
199   /*
200    * Initialize floating point unit.
201    */
202   _fpreset ();                  /* Supplied by the runtime library. */
203
204   /*
205    * Set up __argc, __argv and _environ.
206    */
207   _mingw32_init_mainargs ();
208
209   /*
210    * Sets the default file mode for stdin, stdout and stderr, as well
211    * as files later opened by the user, to _CRT_fmode.
212    * NOTE: DLLs don't do this because that would be rude!
213    */
214   _mingw32_init_fmode ();
215
216   /*
217    * Call the main function. If the user does not supply one
218    * the one in the 'libmingw32.a' library will be linked in, and
219    * that one calls WinMain. See main.c in the 'lib' dir
220    * for more details.
221    */
222   nRet = main (_argc, _argv, environ);
223
224   /*
225    * Perform exit processing for the C library. This means
226    * flushing output and calling 'atexit' registered functions.
227    */
228   _cexit ();
229
230   ExitProcess (nRet);
231
232   return 0;
233 }
234
235 /*
236  * The function mainCRTStartup is the entry point for all console programs.
237  */
238 int
239 mainCRTStartup ()
240 {
241 #ifdef __MSVCRT__
242   __set_app_type (__CONSOLE_APP);
243 #endif
244   __mingw_CRTStartup ();
245   return 0;
246 }
247
248 /*
249  * For now the GUI startup function is the same as the console one.
250  * This simply gets rid of the annoying warning about not being able
251  * to find WinMainCRTStartup when linking GUI applications.
252  */
253 int
254 WinMainCRTStartup ()
255 {
256 #ifdef __MSVCRT__
257   __set_app_type (__GUI_APP);
258 #endif
259   __mingw_CRTStartup ();
260 }
261
262 #elif defined(DLLSTARTUP) /* dllcrt0.o - startup for a DLL */
263
264 /* Unlike normal crt1, I don't initialize the FPU, because the process
265  * should have done that already. I also don't set the file handle modes,
266  * because that would be rude. */
267
268 #ifdef  __GNUC__
269 extern void __main ();
270 extern void __do_global_dtors ();
271 #endif
272
273 extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID);
274
275 BOOL WINAPI
276 DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
277 {
278   BOOL bRet;
279
280   if (dwReason == DLL_PROCESS_ATTACH)
281     {
282       _mingw32_init_mainargs ();
283
284 #ifdef  __GNUC__
285       /* From libgcc.a, calls global class constructors. */
286       __main ();
287 #endif
288     }
289
290   /*
291    * Call the user-supplied DllMain subroutine
292    * NOTE: DllMain is optional, so libmingw32.a includes a stub
293    *       which will be used if the user does not supply one.
294    */
295   bRet = DllMain (hDll, dwReason, lpReserved);
296
297 #ifdef  __GNUC__
298   if (dwReason == DLL_PROCESS_DETACH)
299     {
300       /* From libgcc.a, calls global class destructors. */
301       __do_global_dtors ();
302     }
303 #endif
304
305   return bRet;
306 }
307
308 /*
309  * For the moment a dummy atexit. Atexit causes problems in DLLs, especially
310  * if they are dynamically loaded. For now atexit inside a DLL does nothing.
311  * NOTE: We need this even if the DLL author never calls atexit because
312  *       the global constructor function __do_global_ctors called from __main
313  *       will attempt to register __do_global_dtors using atexit.
314  *       Thanks to Andrey A. Smirnov for pointing this one out.
315  */
316 int
317 atexit (void (*pfn) ())
318 {
319   return 0;
320 }
321
322 #else
323 #error No startup target!
324 #endif /* EXESTARTUP */