msvcrt: Use the write_invalid_msvcrt_tm helper in _gmtime64_s.
[wine] / dlls / msvcrt / exit.c
1 /*
2  * msvcrt.dll exit functions
3  *
4  * Copyright 2000 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdio.h>
21 #include "msvcrt.h"
22 #include "mtdll.h"
23 #include "winuser.h"
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
27
28 /* MT */
29 #define LOCK_EXIT   _mlock(_EXIT_LOCK1)
30 #define UNLOCK_EXIT _munlock(_EXIT_LOCK1)
31
32 static MSVCRT__onexit_t *MSVCRT_atexit_table = NULL;
33 static int MSVCRT_atexit_table_size = 0;
34 static int MSVCRT_atexit_registered = 0; /* Points to free slot */
35 static MSVCRT_purecall_handler purecall_handler = NULL;
36
37 static const char szMsgBoxTitle[] = "Wine C++ Runtime Library";
38
39 extern int MSVCRT_app_type;
40 extern char *MSVCRT__pgmptr;
41
42 void (*CDECL _aexit_rtn)(int) = MSVCRT__exit;
43
44 /* INTERNAL: call atexit functions */
45 static void __MSVCRT__call_atexit(void)
46 {
47   /* Note: should only be called with the exit lock held */
48   TRACE("%d atext functions to call\n", MSVCRT_atexit_registered);
49   /* Last registered gets executed first */
50   while (MSVCRT_atexit_registered > 0)
51   {
52     MSVCRT_atexit_registered--;
53     TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]);
54     if (MSVCRT_atexit_table[MSVCRT_atexit_registered])
55       (*MSVCRT_atexit_table[MSVCRT_atexit_registered])();
56     TRACE("returned\n");
57   }
58 }
59
60 /*********************************************************************
61  *              __dllonexit (MSVCRT.@)
62  */
63 MSVCRT__onexit_t CDECL __dllonexit(MSVCRT__onexit_t func, MSVCRT__onexit_t **start, MSVCRT__onexit_t **end)
64 {
65   MSVCRT__onexit_t *tmp;
66   int len;
67
68   TRACE("(%p,%p,%p)\n", func, start, end);
69
70   if (!start || !*start || !end || !*end)
71   {
72    FIXME("bad table\n");
73    return NULL;
74   }
75
76   len = (*end - *start);
77
78   TRACE("table start %p-%p, %d entries\n", *start, *end, len);
79
80   if (++len <= 0)
81     return NULL;
82
83   tmp = MSVCRT_realloc(*start, len * sizeof(tmp));
84   if (!tmp)
85     return NULL;
86   *start = tmp;
87   *end = tmp + len;
88   tmp[len - 1] = func;
89   TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
90   return func;
91 }
92
93 /*********************************************************************
94  *              _exit (MSVCRT.@)
95  */
96 void CDECL MSVCRT__exit(int exitcode)
97 {
98   TRACE("(%d)\n", exitcode);
99   ExitProcess(exitcode);
100 }
101
102 /* Print out an error message with an option to debug */
103 static void DoMessageBox(LPCSTR lead, LPCSTR message)
104 {
105   MSGBOXPARAMSA msgbox;
106   char text[2048];
107   INT ret;
108
109   snprintf(text,sizeof(text),"%s\n\nProgram: %s\n%s\n\n"
110                "Press OK to exit the program, or Cancel to start the Wine debugger.\n ",
111                lead, MSVCRT__pgmptr, message);
112
113   msgbox.cbSize = sizeof(msgbox);
114   msgbox.hwndOwner = GetActiveWindow();
115   msgbox.hInstance = 0;
116   msgbox.lpszText = text;
117   msgbox.lpszCaption = szMsgBoxTitle;
118   msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
119   msgbox.lpszIcon = NULL;
120   msgbox.dwContextHelpId = 0;
121   msgbox.lpfnMsgBoxCallback = NULL;
122   msgbox.dwLanguageId = LANG_NEUTRAL;
123
124   ret = MessageBoxIndirectA(&msgbox);
125   if (ret == IDCANCEL)
126     DebugBreak();
127 }
128
129 /*********************************************************************
130  *              _amsg_exit (MSVCRT.@)
131  */
132 void CDECL _amsg_exit(int errnum)
133 {
134   TRACE("(%d)\n", errnum);
135   /* FIXME: text for the error number. */
136   if (MSVCRT_app_type == 2)
137   {
138     char text[32];
139     sprintf(text, "Error: R60%d",errnum);
140     DoMessageBox("Runtime error!", text);
141   }
142   else
143     _cprintf("\nruntime error R60%d\n",errnum);
144   _aexit_rtn(255);
145 }
146
147 /*********************************************************************
148  *              abort (MSVCRT.@)
149  */
150 void CDECL MSVCRT_abort(void)
151 {
152   TRACE("()\n");
153   if (MSVCRT_app_type == 2)
154   {
155     DoMessageBox("Runtime error!", "abnormal program termination");
156   }
157   else
158     _cputs("\nabnormal program termination\n");
159   MSVCRT_raise(MSVCRT_SIGABRT);
160   /* in case raise() returns */
161   MSVCRT__exit(3);
162 }
163
164 /*********************************************************************
165  *              _assert (MSVCRT.@)
166  */
167 void CDECL MSVCRT__assert(const char* str, const char* file, unsigned int line)
168 {
169   TRACE("(%s,%s,%d)\n",str,file,line);
170   if (MSVCRT_app_type == 2)
171   {
172     char text[2048];
173     snprintf(text, sizeof(text), "File: %s\nLine: %d\n\nExpression: \"%s\"", file, line, str);
174     DoMessageBox("Assertion failed!", text);
175   }
176   else
177     _cprintf("Assertion failed: %s, file %s, line %d\n\n",str, file, line);
178   MSVCRT_raise(MSVCRT_SIGABRT);
179   /* in case raise() returns */
180   MSVCRT__exit(3);
181 }
182
183 /*********************************************************************
184  *              _c_exit (MSVCRT.@)
185  */
186 void CDECL MSVCRT__c_exit(void)
187 {
188   TRACE("(void)\n");
189   /* All cleanup is done on DLL detach; Return to caller */
190 }
191
192 /*********************************************************************
193  *              _cexit (MSVCRT.@)
194  */
195 void CDECL MSVCRT__cexit(void)
196 {
197   TRACE("(void)\n");
198   LOCK_EXIT;
199   __MSVCRT__call_atexit();
200   UNLOCK_EXIT;
201 }
202
203 /*********************************************************************
204  *              _onexit (MSVCRT.@)
205  */
206 MSVCRT__onexit_t CDECL MSVCRT__onexit(MSVCRT__onexit_t func)
207 {
208   TRACE("(%p)\n",func);
209
210   if (!func)
211     return NULL;
212
213   LOCK_EXIT;
214   if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1)
215   {
216     MSVCRT__onexit_t *newtable;
217     TRACE("expanding table\n");
218     newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32);
219     if (!newtable)
220     {
221       TRACE("failed!\n");
222       UNLOCK_EXIT;
223       return NULL;
224     }
225     memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size);
226     MSVCRT_atexit_table_size += 32;
227     MSVCRT_free (MSVCRT_atexit_table);
228     MSVCRT_atexit_table = newtable;
229   }
230   MSVCRT_atexit_table[MSVCRT_atexit_registered] = func;
231   MSVCRT_atexit_registered++;
232   UNLOCK_EXIT;
233   return func;
234 }
235
236 /*********************************************************************
237  *              exit (MSVCRT.@)
238  */
239 void CDECL MSVCRT_exit(int exitcode)
240 {
241   TRACE("(%d)\n",exitcode);
242   MSVCRT__cexit();
243   ExitProcess(exitcode);
244 }
245
246 /*********************************************************************
247  *              atexit (MSVCRT.@)
248  */
249 int CDECL MSVCRT_atexit(void (*func)(void))
250 {
251   TRACE("(%p)\n", func);
252   return MSVCRT__onexit((MSVCRT__onexit_t)func) == (MSVCRT__onexit_t)func ? 0 : -1;
253 }
254
255 /* _set_purecall_handler - not exported in native msvcrt */
256 MSVCRT_purecall_handler CDECL _set_purecall_handler(MSVCRT_purecall_handler function)
257 {
258     MSVCRT_purecall_handler ret = purecall_handler;
259
260     TRACE("(%p)\n", function);
261     purecall_handler = function;
262     return ret;
263 }
264
265 /*********************************************************************
266  *              _purecall (MSVCRT.@)
267  */
268 void CDECL _purecall(void)
269 {
270   TRACE("(void)\n");
271
272   if(purecall_handler)
273       purecall_handler();
274   _amsg_exit( 25 );
275 }