msvcrt: Import lroundf implementation from musl.
[wine.git] / dlls / msvcrt / misc.c
blob5ea1ddfc6c717f1e9ec6617bfa70b1061aafe75c
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 <stdlib.h>
22 #include <sys/types.h>
24 #include "msvcrt.h"
25 #include "wine/debug.h"
26 #include "ntsecapi.h"
27 #include "windows.h"
28 #include "wine/asm.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
32 static unsigned int output_format;
34 /*********************************************************************
35 * _beep (MSVCRT.@)
37 void CDECL _beep( unsigned int freq, unsigned int duration)
39 TRACE(":Freq %d, Duration %d\n",freq,duration);
40 Beep(freq, duration);
43 /*********************************************************************
44 * srand (MSVCRT.@)
46 void CDECL srand( unsigned int seed )
48 thread_data_t *data = msvcrt_get_thread_data();
49 data->random_seed = seed;
52 /*********************************************************************
53 * rand (MSVCRT.@)
55 int CDECL rand(void)
57 thread_data_t *data = msvcrt_get_thread_data();
59 /* this is the algorithm used by MSVC, according to
60 * http://en.wikipedia.org/wiki/List_of_pseudorandom_number_generators */
61 data->random_seed = data->random_seed * 214013 + 2531011;
62 return (data->random_seed >> 16) & RAND_MAX;
65 /*********************************************************************
66 * rand_s (MSVCRT.@)
68 int CDECL rand_s(unsigned int *pval)
70 if (!pval || !RtlGenRandom(pval, sizeof(*pval)))
72 *_errno() = EINVAL;
73 return EINVAL;
75 return 0;
78 /*********************************************************************
79 * _sleep (MSVCRT.@)
81 void CDECL _sleep(__msvcrt_ulong timeout)
83 TRACE("_sleep for %ld milliseconds\n",timeout);
84 Sleep((timeout)?timeout:1);
87 /*********************************************************************
88 * _lfind (MSVCRT.@)
90 void* CDECL _lfind(const void* match, const void* start,
91 unsigned int* array_size, unsigned int elem_size,
92 int (CDECL *cf)(const void*,const void*) )
94 unsigned int size = *array_size;
95 if (size)
98 if (cf(match, start) == 0)
99 return (void *)start; /* found */
100 start = (const char *)start + elem_size;
101 } while (--size);
102 return NULL;
105 /*********************************************************************
106 * _lfind_s (MSVCRT.@)
108 void* CDECL _lfind_s(const void* match, const void* start,
109 unsigned int* array_size, unsigned int elem_size,
110 int (CDECL *cf)(void*,const void*,const void*),
111 void* context)
113 unsigned int size;
114 if (!MSVCRT_CHECK_PMT(match != NULL)) return NULL;
115 if (!MSVCRT_CHECK_PMT(array_size != NULL)) return NULL;
116 if (!MSVCRT_CHECK_PMT(start != NULL || *array_size == 0)) return NULL;
117 if (!MSVCRT_CHECK_PMT(cf != NULL)) return NULL;
118 if (!MSVCRT_CHECK_PMT(elem_size != 0)) return NULL;
120 size = *array_size;
121 if (size)
124 if (cf(context, match, start) == 0)
125 return (void *)start; /* found */
126 start = (const char *)start + elem_size;
127 } while (--size);
128 return NULL;
131 /*********************************************************************
132 * _lsearch (MSVCRT.@)
134 void* CDECL _lsearch(const void* match, void* start,
135 unsigned int* array_size, unsigned int elem_size,
136 int (CDECL *cf)(const void*,const void*) )
138 unsigned int size = *array_size;
139 if (size)
142 if (cf(match, start) == 0)
143 return start; /* found */
144 start = (char*)start + elem_size;
145 } while (--size);
147 /* not found, add to end */
148 memcpy(start, match, elem_size);
149 array_size[0]++;
150 return start;
153 /*********************************************************************
154 * bsearch_s (msvcrt.@)
156 void* CDECL bsearch_s(const void *key, const void *base, size_t nmemb, size_t size,
157 int (__cdecl *compare)(void *, const void *, const void *), void *ctx)
159 ssize_t min = 0;
160 ssize_t max = nmemb - 1;
162 if (!MSVCRT_CHECK_PMT(size != 0)) return NULL;
163 if (!MSVCRT_CHECK_PMT(compare != NULL)) return NULL;
165 while (min <= max)
167 ssize_t cursor = min + (max - min) / 2;
168 int ret = compare(ctx, key,(const char *)base+(cursor*size));
169 if (!ret)
170 return (char*)base+(cursor*size);
171 if (ret < 0)
172 max = cursor - 1;
173 else
174 min = cursor + 1;
176 return NULL;
179 static int CDECL compare_wrapper(void *ctx, const void *e1, const void *e2)
181 int (__cdecl *compare)(const void *, const void *) = ctx;
182 return compare(e1, e2);
185 /*********************************************************************
186 * bsearch (msvcrt.@)
188 void* CDECL bsearch(const void *key, const void *base, size_t nmemb,
189 size_t size, int (__cdecl *compar)(const void *, const void *))
191 return bsearch_s(key, base, nmemb, size, compare_wrapper, compar);
193 /*********************************************************************
194 * _chkesp (MSVCRT.@)
196 * Trap to a debugger if the value of the stack pointer has changed.
198 * PARAMS
199 * None.
201 * RETURNS
202 * Does not return.
204 * NOTES
205 * This function is available for iX86 only.
207 * When VC++ generates debug code, it stores the value of the stack pointer
208 * before calling any external function, and checks the value following
209 * the call. It then calls this function, which will trap if the values are
210 * not the same. Usually this means that the prototype used to call
211 * the function is incorrect. It can also mean that the .spec entry has
212 * the wrong calling convention or parameters.
214 #ifdef __i386__
216 # if defined(__GNUC__) || defined(__clang__)
218 __ASM_GLOBAL_FUNC(_chkesp,
219 "jnz 1f\n\t"
220 "ret\n"
221 "1:\tpushl %ebp\n\t"
222 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
223 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
224 "movl %esp,%ebp\n\t"
225 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
226 "subl $12,%esp\n\t"
227 "pushl %eax\n\t"
228 "pushl %ecx\n\t"
229 "pushl %edx\n\t"
230 "call " __ASM_NAME("chkesp_fail") "\n\t"
231 "popl %edx\n\t"
232 "popl %ecx\n\t"
233 "popl %eax\n\t"
234 "leave\n\t"
235 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
236 __ASM_CFI(".cfi_same_value %ebp\n\t")
237 "ret")
239 void CDECL DECLSPEC_HIDDEN chkesp_fail(void)
241 ERR("Stack pointer incorrect after last function call - Bad prototype/spec entry?\n");
242 DebugBreak();
245 # else /* __GNUC__ || __clang__ */
247 /**********************************************************************/
249 void CDECL _chkesp(void)
253 # endif /* __GNUC__ || __clang__ */
255 #endif /* __i386__ */
257 static inline void swap(char *l, char *r, size_t size)
259 char tmp;
261 while(size--) {
262 tmp = *l;
263 *l++ = *r;
264 *r++ = tmp;
268 static void small_sort(void *base, size_t nmemb, size_t size,
269 int (CDECL *compar)(void *, const void *, const void *), void *context)
271 size_t e, i;
272 char *max, *p;
274 for(e=nmemb; e>1; e--) {
275 max = base;
276 for(i=1; i<e; i++) {
277 p = (char*)base + i*size;
278 if(compar(context, p, max) > 0)
279 max = p;
282 if(p != max)
283 swap(p, max, size);
287 static void quick_sort(void *base, size_t nmemb, size_t size,
288 int (CDECL *compar)(void *, const void *, const void *), void *context)
290 size_t stack_lo[8*sizeof(size_t)], stack_hi[8*sizeof(size_t)];
291 size_t beg, end, lo, hi, med;
292 int stack_pos;
294 stack_pos = 0;
295 stack_lo[stack_pos] = 0;
296 stack_hi[stack_pos] = nmemb-1;
298 #define X(i) ((char*)base+size*(i))
299 while(stack_pos >= 0) {
300 beg = stack_lo[stack_pos];
301 end = stack_hi[stack_pos--];
303 if(end-beg < 8) {
304 small_sort(X(beg), end-beg+1, size, compar, context);
305 continue;
308 lo = beg;
309 hi = end;
310 med = lo + (hi-lo+1)/2;
311 if(compar(context, X(lo), X(med)) > 0)
312 swap(X(lo), X(med), size);
313 if(compar(context, X(lo), X(hi)) > 0)
314 swap(X(lo), X(hi), size);
315 if(compar(context, X(med), X(hi)) > 0)
316 swap(X(med), X(hi), size);
318 lo++;
319 hi--;
320 while(1) {
321 while(lo <= hi) {
322 if(lo!=med && compar(context, X(lo), X(med))>0)
323 break;
324 lo++;
327 while(med != hi) {
328 if(compar(context, X(hi), X(med)) <= 0)
329 break;
330 hi--;
333 if(hi < lo)
334 break;
336 swap(X(lo), X(hi), size);
337 if(hi == med)
338 med = lo;
339 lo++;
340 hi--;
343 while(hi > beg) {
344 if(hi!=med && compar(context, X(hi), X(med))!=0)
345 break;
346 hi--;
349 if(hi-beg >= end-lo) {
350 stack_lo[++stack_pos] = beg;
351 stack_hi[stack_pos] = hi;
352 stack_lo[++stack_pos] = lo;
353 stack_hi[stack_pos] = end;
354 }else {
355 stack_lo[++stack_pos] = lo;
356 stack_hi[stack_pos] = end;
357 stack_lo[++stack_pos] = beg;
358 stack_hi[stack_pos] = hi;
361 #undef X
364 /*********************************************************************
365 * qsort_s (MSVCRT.@)
367 * This function is trying to sort data doing identical comparisons
368 * as native does. There are still cases where it behaves differently.
370 void CDECL qsort_s(void *base, size_t nmemb, size_t size,
371 int (CDECL *compar)(void *, const void *, const void *), void *context)
373 const size_t total_size = nmemb*size;
375 if (!MSVCRT_CHECK_PMT(base != NULL || (base == NULL && nmemb == 0))) return;
376 if (!MSVCRT_CHECK_PMT(size > 0)) return;
377 if (!MSVCRT_CHECK_PMT(compar != NULL)) return;
378 if (total_size / size != nmemb) return;
380 if (nmemb < 2) return;
382 quick_sort(base, nmemb, size, compar, context);
385 /*********************************************************************
386 * qsort (MSVCRT.@)
388 void CDECL qsort(void *base, size_t nmemb, size_t size,
389 int (CDECL *compar)(const void*, const void*))
391 qsort_s(base, nmemb, size, compare_wrapper, compar);
394 /*********************************************************************
395 * _get_output_format (MSVCRT.@)
397 unsigned int CDECL _get_output_format(void)
399 return output_format;
402 /*********************************************************************
403 * _set_output_format (MSVCRT.@)
405 unsigned int CDECL _set_output_format(unsigned int new_output_format)
407 unsigned int ret = output_format;
409 if(!MSVCRT_CHECK_PMT(new_output_format==0 || new_output_format==_TWO_DIGIT_EXPONENT))
410 return ret;
412 output_format = new_output_format;
413 return ret;
416 /*********************************************************************
417 * _resetstkoflw (MSVCRT.@)
419 int CDECL _resetstkoflw(void)
421 int stack_addr;
422 DWORD oldprot;
424 /* causes stack fault that updates NtCurrentTeb()->Tib.StackLimit */
425 return VirtualProtect(&stack_addr, 1, PAGE_GUARD|PAGE_READWRITE, &oldprot);
428 #if _MSVCR_VER>=80 && _MSVCR_VER<=90
430 /*********************************************************************
431 * _decode_pointer (MSVCR80.@)
433 void * CDECL _decode_pointer(void * ptr)
435 return DecodePointer(ptr);
438 /*********************************************************************
439 * _encode_pointer (MSVCR80.@)
441 void * CDECL _encode_pointer(void * ptr)
443 return EncodePointer(ptr);
446 #endif /* _MSVCR_VER>=80 && _MSVCR_VER<=90 */
448 #if _MSVCR_VER>=80 && _MSVCR_VER<=100
449 /*********************************************************************
450 * _encoded_null (MSVCR80.@)
452 void * CDECL _encoded_null(void)
454 TRACE("\n");
456 return EncodePointer(NULL);
458 #endif
460 #if _MSVCR_VER>=70
461 /*********************************************************************
462 * _CRT_RTC_INIT (MSVCR70.@)
464 void* CDECL _CRT_RTC_INIT(void *unk1, void *unk2, int unk3, int unk4, int unk5)
466 TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
467 return NULL;
469 #endif
471 #if _MSVCR_VER>=80
473 /*********************************************************************
474 * _CRT_RTC_INITW (MSVCR80.@)
476 void* CDECL _CRT_RTC_INITW(void *unk1, void *unk2, int unk3, int unk4, int unk5)
478 TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
479 return NULL;
482 /*********************************************************************
483 * _byteswap_ushort (MSVCR80.@)
485 unsigned short CDECL _byteswap_ushort(unsigned short s)
487 return (s<<8) + (s>>8);
490 /*********************************************************************
491 * _byteswap_ulong (MSVCR80.@)
493 ULONG CDECL _byteswap_ulong(ULONG l)
495 return (l<<24) + ((l<<8)&0xFF0000) + ((l>>8)&0xFF00) + (l>>24);
498 /*********************************************************************
499 * _byteswap_uint64 (MSVCR80.@)
501 unsigned __int64 CDECL _byteswap_uint64(unsigned __int64 i)
503 return (i<<56) + ((i&0xFF00)<<40) + ((i&0xFF0000)<<24) + ((i&0xFF000000)<<8) +
504 ((i>>8)&0xFF000000) + ((i>>24)&0xFF0000) + ((i>>40)&0xFF00) + (i>>56);
507 #endif /* _MSVCR_VER>=80 */
509 #if _MSVCR_VER>=110
511 /*********************************************************************
512 * __crtGetShowWindowMode (MSVCR110.@)
514 int CDECL __crtGetShowWindowMode(void)
516 STARTUPINFOW si;
518 GetStartupInfoW(&si);
519 TRACE("flags=%x window=%d\n", si.dwFlags, si.wShowWindow);
520 return si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT;
523 /*********************************************************************
524 * __crtInitializeCriticalSectionEx (MSVCR110.@)
526 BOOL CDECL __crtInitializeCriticalSectionEx(
527 CRITICAL_SECTION *cs, DWORD spin_count, DWORD flags)
529 TRACE("(%p %x %x)\n", cs, spin_count, flags);
530 return InitializeCriticalSectionEx(cs, spin_count, flags);
533 #endif /* _MSVCR_VER>=110 */
535 #if _MSVCR_VER>=120
536 /*********************************************************************
537 * _vacopy (MSVCR120.@)
539 void CDECL _vacopy(__ms_va_list *dest, __ms_va_list src)
541 __ms_va_copy(*dest, src);
543 #endif
545 #if _MSVCR_VER>=80
546 /*********************************************************************
547 * _crt_debugger_hook (MSVCR80.@)
549 void CDECL _crt_debugger_hook(int reserved)
551 WARN("(%x)\n", reserved);
553 #endif
555 #if _MSVCR_VER>=110
556 /*********************************************************************
557 * __crtUnhandledException (MSVCR110.@)
559 LONG CDECL __crtUnhandledException(EXCEPTION_POINTERS *ep)
561 TRACE("(%p)\n", ep);
562 SetUnhandledExceptionFilter(NULL);
563 return UnhandledExceptionFilter(ep);
566 /* ?_Trace_agents@Concurrency@@YAXW4Agents_EventType@1@_JZZ */
567 void WINAPIV _Trace_agents(/*enum Concurrency::Agents_EventType*/int type, __int64 id, ...)
569 FIXME("(%d %s)\n", type, wine_dbgstr_longlong(id));
571 #endif
573 #if _MSVCR_VER>=120
574 /*********************************************************************
575 * __crtSleep (MSVCR120.@)
577 void CDECL __crtSleep(DWORD timeout)
579 TRACE("(%u)\n", timeout);
580 Sleep(timeout);
583 /*********************************************************************
584 * _SetWinRTOutOfMemoryExceptionCallback (MSVCR120.@)
586 void CDECL _SetWinRTOutOfMemoryExceptionCallback(void *callback)
588 FIXME("(%p): stub\n", callback);
590 #endif