include: Move inline assembly definitions to a new wine/asm.h header.
[wine.git] / dlls / msvcrt / misc.c
blobae81fbf5cdbd8461e69bd3314d63b39b4effa9dd
1 /*
2 * msvcrt.dll misc functions
4 * Copyright 2000 Jon Griffiths
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdlib.h>
26 #include "msvcrt.h"
27 #include "wine/debug.h"
28 #include "ntsecapi.h"
29 #include "windows.h"
30 #include "wine/asm.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
34 static unsigned int output_format;
36 /*********************************************************************
37 * _beep (MSVCRT.@)
39 void CDECL MSVCRT__beep( unsigned int freq, unsigned int duration)
41 TRACE(":Freq %d, Duration %d\n",freq,duration);
42 Beep(freq, duration);
45 /*********************************************************************
46 * srand (MSVCRT.@)
48 void CDECL MSVCRT_srand( unsigned int seed )
50 thread_data_t *data = msvcrt_get_thread_data();
51 data->random_seed = seed;
54 /*********************************************************************
55 * rand (MSVCRT.@)
57 int CDECL MSVCRT_rand(void)
59 thread_data_t *data = msvcrt_get_thread_data();
61 /* this is the algorithm used by MSVC, according to
62 * http://en.wikipedia.org/wiki/List_of_pseudorandom_number_generators */
63 data->random_seed = data->random_seed * 214013 + 2531011;
64 return (data->random_seed >> 16) & MSVCRT_RAND_MAX;
67 /*********************************************************************
68 * rand_s (MSVCRT.@)
70 int CDECL MSVCRT_rand_s(unsigned int *pval)
72 if (!pval || !RtlGenRandom(pval, sizeof(*pval)))
74 *MSVCRT__errno() = MSVCRT_EINVAL;
75 return MSVCRT_EINVAL;
77 return 0;
80 /*********************************************************************
81 * _sleep (MSVCRT.@)
83 void CDECL MSVCRT__sleep(MSVCRT_ulong timeout)
85 TRACE("_sleep for %d milliseconds\n",timeout);
86 Sleep((timeout)?timeout:1);
89 /*********************************************************************
90 * _lfind (MSVCRT.@)
92 void* CDECL _lfind(const void* match, const void* start,
93 unsigned int* array_size, unsigned int elem_size,
94 int (CDECL *cf)(const void*,const void*) )
96 unsigned int size = *array_size;
97 if (size)
100 if (cf(match, start) == 0)
101 return (void *)start; /* found */
102 start = (const char *)start + elem_size;
103 } while (--size);
104 return NULL;
107 /*********************************************************************
108 * _lfind_s (MSVCRT.@)
110 void* CDECL _lfind_s(const void* match, const void* start,
111 unsigned int* array_size, unsigned int elem_size,
112 int (CDECL *cf)(void*,const void*,const void*),
113 void* context)
115 unsigned int size;
116 if (!MSVCRT_CHECK_PMT(match != NULL)) return NULL;
117 if (!MSVCRT_CHECK_PMT(array_size != NULL)) return NULL;
118 if (!MSVCRT_CHECK_PMT(start != NULL || *array_size == 0)) return NULL;
119 if (!MSVCRT_CHECK_PMT(cf != NULL)) return NULL;
120 if (!MSVCRT_CHECK_PMT(elem_size != 0)) return NULL;
122 size = *array_size;
123 if (size)
126 if (cf(context, match, start) == 0)
127 return (void *)start; /* found */
128 start = (const char *)start + elem_size;
129 } while (--size);
130 return NULL;
133 /*********************************************************************
134 * _lsearch (MSVCRT.@)
136 void* CDECL _lsearch(const void* match, void* start,
137 unsigned int* array_size, unsigned int elem_size,
138 int (CDECL *cf)(const void*,const void*) )
140 unsigned int size = *array_size;
141 if (size)
144 if (cf(match, start) == 0)
145 return start; /* found */
146 start = (char*)start + elem_size;
147 } while (--size);
149 /* not found, add to end */
150 memcpy(start, match, elem_size);
151 array_size[0]++;
152 return start;
155 /*********************************************************************
156 * bsearch_s (msvcrt.@)
158 void* CDECL MSVCRT_bsearch_s(const void *key, const void *base,
159 MSVCRT_size_t nmemb, MSVCRT_size_t size,
160 int (__cdecl *compare)(void *, const void *, const void *), void *ctx)
162 ssize_t min = 0;
163 ssize_t max = nmemb - 1;
165 if (!MSVCRT_CHECK_PMT(size != 0)) return NULL;
166 if (!MSVCRT_CHECK_PMT(compare != NULL)) return NULL;
168 while (min <= max)
170 ssize_t cursor = min + (max - min) / 2;
171 int ret = compare(ctx, key,(const char *)base+(cursor*size));
172 if (!ret)
173 return (char*)base+(cursor*size);
174 if (ret < 0)
175 max = cursor - 1;
176 else
177 min = cursor + 1;
179 return NULL;
182 static int CDECL compare_wrapper(void *ctx, const void *e1, const void *e2)
184 int (__cdecl *compare)(const void *, const void *) = ctx;
185 return compare(e1, e2);
188 /*********************************************************************
189 * bsearch (msvcrt.@)
191 void* CDECL MSVCRT_bsearch(const void *key, const void *base, MSVCRT_size_t nmemb,
192 MSVCRT_size_t size, int (__cdecl *compar)(const void *, const void *))
194 return MSVCRT_bsearch_s(key, base, nmemb, size, compare_wrapper, compar);
196 /*********************************************************************
197 * _chkesp (MSVCRT.@)
199 * Trap to a debugger if the value of the stack pointer has changed.
201 * PARAMS
202 * None.
204 * RETURNS
205 * Does not return.
207 * NOTES
208 * This function is available for iX86 only.
210 * When VC++ generates debug code, it stores the value of the stack pointer
211 * before calling any external function, and checks the value following
212 * the call. It then calls this function, which will trap if the values are
213 * not the same. Usually this means that the prototype used to call
214 * the function is incorrect. It can also mean that the .spec entry has
215 * the wrong calling convention or parameters.
217 #ifdef __i386__
219 # ifdef __GNUC__
221 __ASM_GLOBAL_FUNC(_chkesp,
222 "jnz 1f\n\t"
223 "ret\n"
224 "1:\tpushl %ebp\n\t"
225 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
226 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
227 "movl %esp,%ebp\n\t"
228 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
229 "subl $12,%esp\n\t"
230 "pushl %eax\n\t"
231 "pushl %ecx\n\t"
232 "pushl %edx\n\t"
233 "call " __ASM_NAME("MSVCRT_chkesp_fail") "\n\t"
234 "popl %edx\n\t"
235 "popl %ecx\n\t"
236 "popl %eax\n\t"
237 "leave\n\t"
238 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
239 __ASM_CFI(".cfi_same_value %ebp\n\t")
240 "ret")
242 void CDECL DECLSPEC_HIDDEN MSVCRT_chkesp_fail(void)
244 ERR("Stack pointer incorrect after last function call - Bad prototype/spec entry?\n");
245 DebugBreak();
248 # else /* __GNUC__ */
250 /**********************************************************************/
252 void CDECL _chkesp(void)
256 # endif /* __GNUC__ */
258 #endif /* __i386__ */
260 static inline void swap(char *l, char *r, MSVCRT_size_t size)
262 char tmp;
264 while(size--) {
265 tmp = *l;
266 *l++ = *r;
267 *r++ = tmp;
271 static void small_sort(void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size,
272 int (CDECL *compar)(void *, const void *, const void *), void *context)
274 MSVCRT_size_t e, i;
275 char *max, *p;
277 for(e=nmemb; e>1; e--) {
278 max = base;
279 for(i=1; i<e; i++) {
280 p = (char*)base + i*size;
281 if(compar(context, p, max) > 0)
282 max = p;
285 if(p != max)
286 swap(p, max, size);
290 static void quick_sort(void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size,
291 int (CDECL *compar)(void *, const void *, const void *), void *context)
293 MSVCRT_size_t stack_lo[8*sizeof(MSVCRT_size_t)], stack_hi[8*sizeof(MSVCRT_size_t)];
294 MSVCRT_size_t beg, end, lo, hi, med;
295 int stack_pos;
297 stack_pos = 0;
298 stack_lo[stack_pos] = 0;
299 stack_hi[stack_pos] = nmemb-1;
301 #define X(i) ((char*)base+size*(i))
302 while(stack_pos >= 0) {
303 beg = stack_lo[stack_pos];
304 end = stack_hi[stack_pos--];
306 if(end-beg < 8) {
307 small_sort(X(beg), end-beg+1, size, compar, context);
308 continue;
311 lo = beg;
312 hi = end;
313 med = lo + (hi-lo+1)/2;
314 if(compar(context, X(lo), X(med)) > 0)
315 swap(X(lo), X(med), size);
316 if(compar(context, X(lo), X(hi)) > 0)
317 swap(X(lo), X(hi), size);
318 if(compar(context, X(med), X(hi)) > 0)
319 swap(X(med), X(hi), size);
321 lo++;
322 hi--;
323 while(1) {
324 while(lo <= hi) {
325 if(lo!=med && compar(context, X(lo), X(med))>0)
326 break;
327 lo++;
330 while(med != hi) {
331 if(compar(context, X(hi), X(med)) <= 0)
332 break;
333 hi--;
336 if(hi < lo)
337 break;
339 swap(X(lo), X(hi), size);
340 if(hi == med)
341 med = lo;
342 lo++;
343 hi--;
346 while(hi > beg) {
347 if(hi!=med && compar(context, X(hi), X(med))!=0)
348 break;
349 hi--;
352 if(hi-beg >= end-lo) {
353 stack_lo[++stack_pos] = beg;
354 stack_hi[stack_pos] = hi;
355 stack_lo[++stack_pos] = lo;
356 stack_hi[stack_pos] = end;
357 }else {
358 stack_lo[++stack_pos] = lo;
359 stack_hi[stack_pos] = end;
360 stack_lo[++stack_pos] = beg;
361 stack_hi[stack_pos] = hi;
364 #undef X
367 /*********************************************************************
368 * qsort_s (MSVCRT.@)
370 * This function is trying to sort data doing identical comparisons
371 * as native does. There are still cases where it behaves differently.
373 void CDECL MSVCRT_qsort_s(void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size,
374 int (CDECL *compar)(void *, const void *, const void *), void *context)
376 const MSVCRT_size_t total_size = nmemb*size;
378 if (!MSVCRT_CHECK_PMT(base != NULL || (base == NULL && nmemb == 0))) return;
379 if (!MSVCRT_CHECK_PMT(size > 0)) return;
380 if (!MSVCRT_CHECK_PMT(compar != NULL)) return;
381 if (total_size / size != nmemb) return;
383 if (nmemb < 2) return;
385 quick_sort(base, nmemb, size, compar, context);
388 /*********************************************************************
389 * qsort (MSVCRT.@)
391 void CDECL MSVCRT_qsort(void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size,
392 int (CDECL *compar)(const void*, const void*))
394 MSVCRT_qsort_s(base, nmemb, size, compare_wrapper, compar);
397 /*********************************************************************
398 * _get_output_format (MSVCRT.@)
400 unsigned int CDECL MSVCRT__get_output_format(void)
402 return output_format;
405 /*********************************************************************
406 * _set_output_format (MSVCRT.@)
408 unsigned int CDECL MSVCRT__set_output_format(unsigned int new_output_format)
410 unsigned int ret = output_format;
412 if(!MSVCRT_CHECK_PMT(new_output_format==0 || new_output_format==MSVCRT__TWO_DIGIT_EXPONENT))
413 return ret;
415 output_format = new_output_format;
416 return ret;
419 /*********************************************************************
420 * _resetstkoflw (MSVCRT.@)
422 int CDECL MSVCRT__resetstkoflw(void)
424 int stack_addr;
425 DWORD oldprot;
427 /* causes stack fault that updates NtCurrentTeb()->Tib.StackLimit */
428 return VirtualProtect(&stack_addr, 1, PAGE_GUARD|PAGE_READWRITE, &oldprot);
431 #if _MSVCR_VER>=80 && _MSVCR_VER<=90
433 /*********************************************************************
434 * _decode_pointer (MSVCR80.@)
436 void * CDECL MSVCRT_decode_pointer(void * ptr)
438 return DecodePointer(ptr);
441 /*********************************************************************
442 * _encode_pointer (MSVCR80.@)
444 void * CDECL MSVCRT_encode_pointer(void * ptr)
446 return EncodePointer(ptr);
449 #endif /* _MSVCR_VER>=80 && _MSVCR_VER<=90 */
451 #if _MSVCR_VER>=80 && _MSVCR_VER<=100
452 /*********************************************************************
453 * _encoded_null (MSVCR80.@)
455 void * CDECL _encoded_null(void)
457 TRACE("\n");
459 return EncodePointer(NULL);
461 #endif
463 #if _MSVCR_VER>=70
464 /*********************************************************************
465 * _CRT_RTC_INIT (MSVCR70.@)
467 void* CDECL _CRT_RTC_INIT(void *unk1, void *unk2, int unk3, int unk4, int unk5)
469 TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
470 return NULL;
472 #endif
474 #if _MSVCR_VER>=80
476 /*********************************************************************
477 * _CRT_RTC_INITW (MSVCR80.@)
479 void* CDECL _CRT_RTC_INITW(void *unk1, void *unk2, int unk3, int unk4, int unk5)
481 TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
482 return NULL;
485 /*********************************************************************
486 * _byteswap_ushort (MSVCR80.@)
488 unsigned short CDECL _byteswap_ushort(unsigned short s)
490 return (s<<8) + (s>>8);
493 /*********************************************************************
494 * _byteswap_ulong (MSVCR80.@)
496 ULONG CDECL MSVCRT__byteswap_ulong(ULONG l)
498 return (l<<24) + ((l<<8)&0xFF0000) + ((l>>8)&0xFF00) + (l>>24);
501 /*********************************************************************
502 * _byteswap_uint64 (MSVCR80.@)
504 unsigned __int64 CDECL _byteswap_uint64(unsigned __int64 i)
506 return (i<<56) + ((i&0xFF00)<<40) + ((i&0xFF0000)<<24) + ((i&0xFF000000)<<8) +
507 ((i>>8)&0xFF000000) + ((i>>24)&0xFF0000) + ((i>>40)&0xFF00) + (i>>56);
510 #endif /* _MSVCR_VER>=80 */
512 #if _MSVCR_VER>=110
514 /*********************************************************************
515 * __crtGetShowWindowMode (MSVCR110.@)
517 int CDECL MSVCR110__crtGetShowWindowMode(void)
519 STARTUPINFOW si;
521 GetStartupInfoW(&si);
522 TRACE("flags=%x window=%d\n", si.dwFlags, si.wShowWindow);
523 return si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT;
526 /*********************************************************************
527 * __crtInitializeCriticalSectionEx (MSVCR110.@)
529 BOOL CDECL MSVCR110__crtInitializeCriticalSectionEx(
530 CRITICAL_SECTION *cs, DWORD spin_count, DWORD flags)
532 TRACE("(%p %x %x)\n", cs, spin_count, flags);
533 return InitializeCriticalSectionEx(cs, spin_count, flags);
536 #endif /* _MSVCR_VER>=110 */
538 #if _MSVCR_VER>=120
539 /*********************************************************************
540 * _vacopy (MSVCR120.@)
542 void CDECL MSVCR120__vacopy(__ms_va_list *dest, __ms_va_list src)
544 __ms_va_copy(*dest, src);
546 #endif
548 #if _MSVCR_VER>=80
549 /*********************************************************************
550 * _crt_debugger_hook (MSVCR80.@)
552 void CDECL MSVCRT__crt_debugger_hook(int reserved)
554 WARN("(%x)\n", reserved);
556 #endif
558 #if _MSVCR_VER>=110
559 /*********************************************************************
560 * __crtUnhandledException (MSVCR110.@)
562 LONG CDECL MSVCRT__crtUnhandledException(EXCEPTION_POINTERS *ep)
564 TRACE("(%p)\n", ep);
565 SetUnhandledExceptionFilter(NULL);
566 return UnhandledExceptionFilter(ep);
569 /* ?_Trace_agents@Concurrency@@YAXW4Agents_EventType@1@_JZZ */
570 void WINAPIV _Trace_agents(/*enum Concurrency::Agents_EventType*/int type, __int64 id, ...)
572 FIXME("(%d %s)\n", type, wine_dbgstr_longlong(id));
574 #endif
576 #if _MSVCR_VER>=120
577 /*********************************************************************
578 * __crtSleep (MSVCR120.@)
580 void CDECL MSVCRT__crtSleep(DWORD timeout)
582 TRACE("(%u)\n", timeout);
583 Sleep(timeout);
586 /*********************************************************************
587 * _SetWinRTOutOfMemoryExceptionCallback (MSVCR120.@)
589 void CDECL MSVCR120__SetWinRTOutOfMemoryExceptionCallback(void *callback)
591 FIXME("(%p): stub\n", callback);
593 #endif