1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23// This file contains portable stdlib functions for SDL
24
25#include "../libm/math_libm.h"
26
27double SDL_atan(double x)
28{
29#ifdef HAVE_ATAN
30 return atan(x);
31#else
32 return SDL_uclibc_atan(x);
33#endif
34}
35
36float SDL_atanf(float x)
37{
38#ifdef HAVE_ATANF
39 return atanf(x);
40#else
41 return (float)SDL_atan((double)x);
42#endif
43}
44
45double SDL_atan2(double y, double x)
46{
47#ifdef HAVE_ATAN2
48 return atan2(y, x);
49#else
50 return SDL_uclibc_atan2(y, x);
51#endif
52}
53
54float SDL_atan2f(float y, float x)
55{
56#ifdef HAVE_ATAN2F
57 return atan2f(y, x);
58#else
59 return (float)SDL_atan2((double)y, (double)x);
60#endif
61}
62
63double SDL_acos(double val)
64{
65#ifdef HAVE_ACOS
66 return acos(val);
67#else
68 double result;
69 if (val == -1.0) {
70 result = SDL_PI_D;
71 } else {
72 result = SDL_atan(SDL_sqrt(1.0 - val * val) / val);
73 if (result < 0.0) {
74 result += SDL_PI_D;
75 }
76 }
77 return result;
78#endif
79}
80
81float SDL_acosf(float val)
82{
83#ifdef HAVE_ACOSF
84 return acosf(val);
85#else
86 return (float)SDL_acos((double)val);
87#endif
88}
89
90double SDL_asin(double val)
91{
92#ifdef HAVE_ASIN
93 return asin(val);
94#else
95 double result;
96 if (val == -1.0) {
97 result = -(SDL_PI_D / 2.0);
98 } else {
99 result = (SDL_PI_D / 2.0) - SDL_acos(val);
100 }
101 return result;
102#endif
103}
104
105float SDL_asinf(float val)
106{
107#ifdef HAVE_ASINF
108 return asinf(val);
109#else
110 return (float)SDL_asin((double)val);
111#endif
112}
113
114double SDL_ceil(double x)
115{
116#ifdef HAVE_CEIL
117 return ceil(x);
118#else
119 double integer = SDL_floor(x);
120 double fraction = x - integer;
121 if (fraction > 0.0) {
122 integer += 1.0;
123 }
124 return integer;
125#endif // HAVE_CEIL
126}
127
128float SDL_ceilf(float x)
129{
130#ifdef HAVE_CEILF
131 return ceilf(x);
132#else
133 return (float)SDL_ceil((double)x);
134#endif
135}
136
137double SDL_copysign(double x, double y)
138{
139#ifdef HAVE_COPYSIGN
140 return copysign(x, y);
141#elif defined(HAVE__COPYSIGN)
142 return _copysign(x, y);
143#elif defined(__WATCOMC__) && defined(__386__)
144 // this is nasty as hell, but it works..
145 unsigned int *xi = (unsigned int *)&x,
146 *yi = (unsigned int *)&y;
147 xi[1] = (yi[1] & 0x80000000) | (xi[1] & 0x7fffffff);
148 return x;
149#else
150 return SDL_uclibc_copysign(x, y);
151#endif // HAVE_COPYSIGN
152}
153
154float SDL_copysignf(float x, float y)
155{
156#ifdef HAVE_COPYSIGNF
157 return copysignf(x, y);
158#else
159 return (float)SDL_copysign((double)x, (double)y);
160#endif
161}
162
163double SDL_cos(double x)
164{
165#ifdef HAVE_COS
166 return cos(x);
167#else
168 return SDL_uclibc_cos(x);
169#endif
170}
171
172float SDL_cosf(float x)
173{
174#ifdef HAVE_COSF
175 return cosf(x);
176#else
177 return (float)SDL_cos((double)x);
178#endif
179}
180
181double SDL_exp(double x)
182{
183#ifdef HAVE_EXP
184 return exp(x);
185#else
186 return SDL_uclibc_exp(x);
187#endif
188}
189
190float SDL_expf(float x)
191{
192#ifdef HAVE_EXPF
193 return expf(x);
194#else
195 return (float)SDL_exp((double)x);
196#endif
197}
198
199double SDL_fabs(double x)
200{
201#ifdef HAVE_FABS
202 return fabs(x);
203#else
204 return SDL_uclibc_fabs(x);
205#endif
206}
207
208float SDL_fabsf(float x)
209{
210#ifdef HAVE_FABSF
211 return fabsf(x);
212#else
213 return (float)SDL_fabs((double)x);
214#endif
215}
216
217double SDL_floor(double x)
218{
219#ifdef HAVE_FLOOR
220 return floor(x);
221#else
222 return SDL_uclibc_floor(x);
223#endif
224}
225
226float SDL_floorf(float x)
227{
228#ifdef HAVE_FLOORF
229 return floorf(x);
230#else
231 return (float)SDL_floor((double)x);
232#endif
233}
234
235double SDL_trunc(double x)
236{
237#ifdef HAVE_TRUNC
238 return trunc(x);
239#else
240 if (x >= 0.0f) {
241 return SDL_floor(x);
242 } else {
243 return SDL_ceil(x);
244 }
245#endif
246}
247
248float SDL_truncf(float x)
249{
250#ifdef HAVE_TRUNCF
251 return truncf(x);
252#else
253 return (float)SDL_trunc((double)x);
254#endif
255}
256
257double SDL_fmod(double x, double y)
258{
259#ifdef HAVE_FMOD
260 return fmod(x, y);
261#else
262 return SDL_uclibc_fmod(x, y);
263#endif
264}
265
266float SDL_fmodf(float x, float y)
267{
268#ifdef HAVE_FMODF
269 return fmodf(x, y);
270#else
271 return (float)SDL_fmod((double)x, (double)y);
272#endif
273}
274
275int SDL_isinf(double x)
276{
277#ifdef HAVE_ISINF
278 return isinf(x);
279#else
280 return SDL_uclibc_isinf(x);
281#endif
282}
283
284int SDL_isinff(float x)
285{
286#ifdef HAVE_ISINF_FLOAT_MACRO
287 return isinf(x);
288#elif defined(HAVE_ISINFF)
289 return isinff(x);
290#else
291 return SDL_uclibc_isinff(x);
292#endif
293}
294
295int SDL_isnan(double x)
296{
297#ifdef HAVE_ISNAN
298 return isnan(x);
299#else
300 return SDL_uclibc_isnan(x);
301#endif
302}
303
304int SDL_isnanf(float x)
305{
306#ifdef HAVE_ISNAN_FLOAT_MACRO
307 return isnan(x);
308#elif defined(HAVE_ISNANF)
309 return isnanf(x);
310#else
311 return SDL_uclibc_isnanf(x);
312#endif
313}
314
315double SDL_log(double x)
316{
317#ifdef HAVE_LOG
318 return log(x);
319#else
320 return SDL_uclibc_log(x);
321#endif
322}
323
324float SDL_logf(float x)
325{
326#ifdef HAVE_LOGF
327 return logf(x);
328#else
329 return (float)SDL_log((double)x);
330#endif
331}
332
333double SDL_log10(double x)
334{
335#ifdef HAVE_LOG10
336 return log10(x);
337#else
338 return SDL_uclibc_log10(x);
339#endif
340}
341
342float SDL_log10f(float x)
343{
344#ifdef HAVE_LOG10F
345 return log10f(x);
346#else
347 return (float)SDL_log10((double)x);
348#endif
349}
350
351double SDL_modf(double x, double *y)
352{
353#ifdef HAVE_MODF
354 return modf(x, y);
355#else
356 return SDL_uclibc_modf(x, y);
357#endif
358}
359
360float SDL_modff(float x, float *y)
361{
362#ifdef HAVE_MODFF
363 return modff(x, y);
364#else
365 double double_result, double_y;
366 double_result = SDL_modf((double)x, &double_y);
367 *y = (float)double_y;
368 return (float)double_result;
369#endif
370}
371
372double SDL_pow(double x, double y)
373{
374#ifdef HAVE_POW
375 return pow(x, y);
376#else
377 return SDL_uclibc_pow(x, y);
378#endif
379}
380
381float SDL_powf(float x, float y)
382{
383#ifdef HAVE_POWF
384 return powf(x, y);
385#else
386 return (float)SDL_pow((double)x, (double)y);
387#endif
388}
389
390double SDL_round(double arg)
391{
392#if defined HAVE_ROUND
393 return round(arg);
394#else
395 if (arg >= 0.0) {
396 return SDL_floor(arg + 0.5);
397 } else {
398 return SDL_ceil(arg - 0.5);
399 }
400#endif
401}
402
403float SDL_roundf(float arg)
404{
405#if defined HAVE_ROUNDF
406 return roundf(arg);
407#else
408 return (float)SDL_round((double)arg);
409#endif
410}
411
412long SDL_lround(double arg)
413{
414#if defined HAVE_LROUND
415 return lround(arg);
416#else
417 return (long)SDL_round(arg);
418#endif
419}
420
421long SDL_lroundf(float arg)
422{
423#if defined HAVE_LROUNDF
424 return lroundf(arg);
425#else
426 return (long)SDL_round((double)arg);
427#endif
428}
429
430double SDL_scalbn(double x, int n)
431{
432#ifdef HAVE_SCALBN
433 return scalbn(x, n);
434#elif defined(HAVE__SCALB)
435 return _scalb(x, n);
436#elif defined(HAVE_LIBC) && defined(HAVE_FLOAT_H) && (FLT_RADIX == 2)
437 /* from scalbn(3): If FLT_RADIX equals 2 (which is
438 * usual), then scalbn() is equivalent to ldexp(3). */
439 return ldexp(x, n);
440#else
441 return SDL_uclibc_scalbn(x, n);
442#endif
443}
444
445float SDL_scalbnf(float x, int n)
446{
447#ifdef HAVE_SCALBNF
448 return scalbnf(x, n);
449#else
450 return (float)SDL_scalbn((double)x, n);
451#endif
452}
453
454double SDL_sin(double x)
455{
456#ifdef HAVE_SIN
457 return sin(x);
458#else
459 return SDL_uclibc_sin(x);
460#endif
461}
462
463float SDL_sinf(float x)
464{
465#ifdef HAVE_SINF
466 return sinf(x);
467#else
468 return (float)SDL_sin((double)x);
469#endif
470}
471
472double SDL_sqrt(double x)
473{
474#ifdef HAVE_SQRT
475 return sqrt(x);
476#else
477 return SDL_uclibc_sqrt(x);
478#endif
479}
480
481float SDL_sqrtf(float x)
482{
483#ifdef HAVE_SQRTF
484 return sqrtf(x);
485#else
486 return (float)SDL_sqrt((double)x);
487#endif
488}
489
490double SDL_tan(double x)
491{
492#ifdef HAVE_TAN
493 return tan(x);
494#else
495 return SDL_uclibc_tan(x);
496#endif
497}
498
499float SDL_tanf(float x)
500{
501#ifdef HAVE_TANF
502 return tanf(x);
503#else
504 return (float)SDL_tan((double)x);
505#endif
506}
507
508int SDL_abs(int x)
509{
510#ifdef HAVE_ABS
511 return abs(x);
512#else
513 return (x < 0) ? -x : x;
514#endif
515}
516
517int SDL_isalpha(int x) { return (SDL_isupper(x)) || (SDL_islower(x)); }
518int SDL_isalnum(int x) { return (SDL_isalpha(x)) || (SDL_isdigit(x)); }
519int SDL_isdigit(int x) { return ((x) >= '0') && ((x) <= '9'); }
520int SDL_isxdigit(int x) { return (((x) >= 'A') && ((x) <= 'F')) || (((x) >= 'a') && ((x) <= 'f')) || (SDL_isdigit(x)); }
521int SDL_ispunct(int x) { return (SDL_isgraph(x)) && (!SDL_isalnum(x)); }
522int SDL_isspace(int x) { return ((x) == ' ') || ((x) == '\t') || ((x) == '\r') || ((x) == '\n') || ((x) == '\f') || ((x) == '\v'); }
523int SDL_isupper(int x) { return ((x) >= 'A') && ((x) <= 'Z'); }
524int SDL_islower(int x) { return ((x) >= 'a') && ((x) <= 'z'); }
525int SDL_isprint(int x) { return ((x) >= ' ') && ((x) < '\x7f'); }
526int SDL_isgraph(int x) { return (SDL_isprint(x)) && ((x) != ' '); }
527int SDL_iscntrl(int x) { return (((x) >= '\0') && ((x) <= '\x1f')) || ((x) == '\x7f'); }
528int SDL_toupper(int x) { return ((x) >= 'a') && ((x) <= 'z') ? ('A' + ((x) - 'a')) : (x); }
529int SDL_tolower(int x) { return ((x) >= 'A') && ((x) <= 'Z') ? ('a' + ((x) - 'A')) : (x); }
530int SDL_isblank(int x) { return ((x) == ' ') || ((x) == '\t'); }
531
532void *SDL_aligned_alloc(size_t alignment, size_t size)
533{
534 size_t padding;
535 Uint8 *result = NULL;
536 size_t requested_size = size;
537
538 if (alignment < sizeof(void*)) {
539 alignment = sizeof(void*);
540 }
541 padding = (alignment - (size % alignment));
542
543 if (SDL_size_add_check_overflow(size, alignment, &size) &&
544 SDL_size_add_check_overflow(size, sizeof(void *), &size) &&
545 SDL_size_add_check_overflow(size, padding, &size)) {
546 void *original = SDL_malloc(size);
547 if (original) {
548 // Make sure we have enough space to store the original pointer
549 result = (Uint8 *)original + sizeof(original);
550
551 // Align the pointer we're going to return
552 result += alignment - (((size_t)result) % alignment);
553
554 // Store the original pointer right before the returned value
555 SDL_memcpy(result - sizeof(original), &original, sizeof(original));
556
557 // Initialize the padding to zero
558 if (padding > 0) {
559 SDL_memset(result + requested_size, 0, padding);
560 }
561 }
562 }
563 return result;
564}
565
566void SDL_aligned_free(void *mem)
567{
568 if (mem) {
569 void *original;
570 SDL_memcpy(&original, ((Uint8 *)mem - sizeof(original)), sizeof(original));
571 SDL_free(original);
572 }
573}
574