Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Enforce Unix line endings for shell scripts
*.sh text eol=lf
2 changes: 2 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
docker build . -t tmp
docker build . -f Dockerfile.buildlocal -t builder
docker run --rm -v ${PWD}:/project builder make
docker run --rm -v ${PWD}:/project builder /bin/bash -c "make install && chmod +x tests/parameter_checker/runner.sh && cd tests/parameter_checker && ./runner.sh"
docker run --rm -v ${PWD}:/project builder /bin/bash -c "make install && chmod +x tests/parameter_checker/negative_runner.sh && cd tests/parameter_checker && ./negative_runner.sh"
- uses: actions/upload-artifact@master
with:
name: lib
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ CMakeLists.txt
.idea/
cmake-build-debug/
share/libfunctionpatcher.ld
*.elf
*.rpx
*.wuhb
tests/parameter_checker/build/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/wiiu-env/devkitppc:20240423
FROM ghcr.io/wiiu-env/devkitppc:20250608

WORKDIR tmp_build
COPY . .
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.buildlocal
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM ghcr.io/wiiu-env/devkitppc:20240423
FROM ghcr.io/wiiu-env/devkitppc:20250608

WORKDIR project
25 changes: 11 additions & 14 deletions include/notifications/notifications.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,23 +374,20 @@ NotificationModuleStatus NotificationModule_FinishDynamicNotificationWithShake(N
float durationBeforeFadeOutInSeconds,
float shakeDuration);

// Copy pasted from libcurl...
/* the typechecker doesn't work in C++ (yet) */
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
!defined(__cplusplus)
#include "typecheck-gcc.h"
#ifdef __cplusplus
}
#endif

// Idea taken from libcurl
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
#include "typechecks-gcc.h"
#else
#if defined(__STDC__) && (__STDC__ >= 1)
/* This preprocessor magic that replaces a call with the exact same call is
only done to make sure application authors pass exactly three arguments
to these functions. */
only done to make sure application authors pass exactly three arguments
to these functions. */

#define NotificationModule_SetDefaultValue(type, valueType, param) NotificationModule_SetDefaultValue(type, valueType, param)
#endif /* __STDC__ >= 1 */
#endif /* gcc >= 4.3 && !__cplusplus */


#ifdef __cplusplus
}
#endif
#endif /* gcc >= 4.3 */
172 changes: 172 additions & 0 deletions include/notifications/typechecks-gcc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#ifndef NOTIFICATIONS_TYPECHECK_GCC_H
#define NOTIFICATIONS_TYPECHECK_GCC_H

#ifdef __cplusplus
#include <cstddef> /* For std::nullptr_t */
#else
#include <stddef.h> /* For NULL */
#endif

/* * Warning generators (Common to C and C++)
* These define static functions that trigger a compiler warning when called.
*/
#define _NM_WARNING(id, message) \
static void __attribute__((__warning__(message))) \
__attribute__((__unused__)) __attribute__((__noinline__)) \
id(void) { __asm__(""); }

#ifdef __cplusplus
extern "C" {
#endif

_NM_WARNING(_nm_warn_NMColor, "NotificationModule_SetDefaultValue expects 'NMColor' for this option.")
_NM_WARNING(_nm_warn_float, "NotificationModule_SetDefaultValue expects 'float' or 'double' for this option.")
_NM_WARNING(_nm_warn_callback, "NotificationModule_SetDefaultValue expects 'NotificationModuleNotificationFinishedCallback' for this option.")
_NM_WARNING(_nm_warn_context, "NotificationModule_SetDefaultValue expects 'void*' for this option.")
_NM_WARNING(_nm_warn_bool, "NotificationModule_SetDefaultValue expects 'bool' (or 'int') for this option.")

#ifdef __cplusplus
}
#endif


/* =========================================================================
* IMPLEMENTATION SELECTION
* ========================================================================= */

#if defined(__cplusplus)

/* ==========================================
* C++17 Implementation
* Only active if -std=c++17 or higher is used.
* ========================================== */
#if __cplusplus >= 201703L

namespace NM_Check {
/* NMColor Checker */
inline bool check_NMColor(NMColor) { return true; }
inline bool check_NMColor(void *) { return false; } /* Sink for NULL */
template<typename T>
inline bool check_NMColor(T) { return false; }

/* Float Checker (accepts float/double) */
inline bool check_float(float) { return true; }
inline bool check_float(double) { return true; }
inline bool check_float(void *) { return false; } /* Sink for NULL */
template<typename T>
inline bool check_float(T) { return false; }

/* Bool Checker (accepts bool/int) */
inline bool check_bool(bool) { return true; }
inline bool check_bool(int) { return true; }
inline bool check_bool(void *) { return false; } /* Sink for NULL */
template<typename T>
inline bool check_bool(T) { return false; }

/* Callback Checker */
inline bool check_callback(NotificationModuleNotificationFinishedCallback) { return true; }
/* Explicit void* (e.g. casting) */
inline bool check_callback(void *) { return true; }
inline bool check_callback(int i) { return i == 0; }
inline bool check_callback(long i) { return i == 0; }
inline bool check_callback(std::nullptr_t) { return true; }
template<typename T>
inline bool check_callback(T) { return false; }

/* Context Checker */
inline bool check_context(void *) { return true; }
inline bool check_context(int i) { return i == 0; }
inline bool check_context(long i) { return i == 0; }
inline bool check_context(std::nullptr_t) { return true; }
template<typename T>
inline bool check_context(T) { return false; }
} // namespace NM_Check

/* Macros mapping to C++ namespace calls */
#define _nm_is_NMColor(x) NM_Check::check_NMColor(x)
#define _nm_is_float(x) NM_Check::check_float(x)
#define _nm_is_bool(x) NM_Check::check_bool(x)
#define _nm_is_callback(x) NM_Check::check_callback(x)
#define _nm_is_context(x) NM_Check::check_context(x)

#else
/* ==========================================
* Pre-C++17 Implementation
* Checks are DISABLED to avoid errors in older versions.
* ========================================== */
#define _nm_is_NMColor(x) (1)
#define _nm_is_float(x) (1)
#define _nm_is_bool(x) (1)
#define _nm_is_callback(x) (1)
#define _nm_is_context(x) (1)
#endif

#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L

/* ==========================================
* C11 Implementation (using _Generic)
* ========================================== */

#define _nm_is_NMColor(x) _Generic((x), \
NMColor : 1, \
default : 0)

#define _nm_is_float(x) _Generic((x), \
float : 1, \
double : 1, \
default : 0)

#define _nm_is_bool(x) _Generic((x), \
_Bool : 1, \
int : 1, \
default : 0)

#define _nm_is_callback(x) _Generic((x), \
NotificationModuleNotificationFinishedCallback : 1, \
void * : 1, \
default : 0)

#define _nm_is_context(x) _Generic((x), \
void * : 1, \
default : 0)

#else

/* ==========================================
* Legacy C Implementation
* Partial checking only.
* ========================================== */

#define _nm_is_type(x, type) __builtin_types_compatible_p(__typeof__(x), type)

/* Disable complex checks in old C */
#define _nm_is_NMColor(x) (1)
#define _nm_is_callback(x) (1)
#define _nm_is_context(x) (1)

/* Scalars are safe to check */
#define _nm_is_float(x) (_nm_is_type(x, float) || _nm_is_type(x, double))
#define _nm_is_bool(x) (_nm_is_type(x, int) || _nm_is_type(x, _Bool))

#endif

#define NotificationModule_SetDefaultValue(type, option, value) \
__extension__({ \
if (__builtin_constant_p(option)) { \
if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_BACKGROUND_COLOR) && !_nm_is_NMColor(value)) \
_nm_warn_NMColor(); \
else if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_TEXT_COLOR) && !_nm_is_NMColor(value)) \
_nm_warn_NMColor(); \
else if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT) && !_nm_is_float(value)) \
_nm_warn_float(); \
else if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_FINISH_FUNCTION) && !_nm_is_callback(value)) \
_nm_warn_callback(); \
else if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_FINISH_FUNCTION_CONTEXT) && !_nm_is_context(value)) \
_nm_warn_context(); \
else if ((option == NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN) && !_nm_is_bool(value)) \
_nm_warn_bool(); \
} \
(NotificationModule_SetDefaultValue)(type, option, value); \
})

#endif /* NOTIFICATIONS_TYPECHECK_GCC_H */
Loading