Give every exported function a declaration, and check that it stays that way
Closes internal-consistency items 7 through 15. Nineteen non-static functions were in the ABI with no declaration anywhere, so no consumer could call them and any consumer could collide with them. The four gamepad_handle_* functions are the ones that mattered: controller.h declared akgl_controller_handle_button_down and three siblings that did not exist, so anything compiled against the header alone failed to link. The definitions carry the declared names now, which also closes Defects -> Known and still open item 10, and their documentation moved to the header. The rest are either declared under a "part of the internal API" block -- akgl_game_save_actors and akgl_game_load_versioncmp, which tests/game.c had to declare for itself, plus six tilemap loader helpers the untested-loader work wants to reach -- or static, which is what the four save iterators and load_objectnamemap should always have been. akgl_path_relative_from is deleted: declared nowhere, called from nowhere, never wrote its output, and leaked a pooled string on every call, so it closes Known and still open item 4 and item 40 by ceasing to exist. scripts/check_api_surface.sh keeps it closed. It reads the built library's dynamic symbol table and every public header with comments stripped, and fails on an exported akgl_* symbol that is declared nowhere. Stripping comments is the whole point -- four of these were mentioned in controller.h prose, which is how they went unnoticed. The pool-size ceilings are defined once, in heap.h, so the #ifndef override hook fires for the first time; actor.h, sprite.h and character.h were defining the same four unconditionally from headers heap.h includes above its own guard. tests/header_pool_override.c fails the compile if that regresses. Also here: (void) rather than () on the twelve no-argument entry points, AKERR_NOIGNORE only on declarations, static helpers with the akgl_ prefix dropped, and the six parameter-name mismatches. akgl_get_json_with_default had its two contexts swapped rather than merely misspelled -- the incoming one was `err` and its own was `e`, which is the name reserved for an incoming one. 24/24 pass, reindent --check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
102
src/controller.c
102
src/controller.c
@@ -182,7 +182,7 @@ static bool keybuffer_take(akgl_Keystroke *dest)
|
||||
return true;
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_list_keyboards(void)
|
||||
akerr_ErrorContext *akgl_controller_list_keyboards(void)
|
||||
{
|
||||
int count;
|
||||
SDL_KeyboardID *keyboards = SDL_GetKeyboards(&count);
|
||||
@@ -206,7 +206,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_list_keyboards(void)
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_open_gamepads(void)
|
||||
akerr_ErrorContext *akgl_controller_open_gamepads(void)
|
||||
{
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
@@ -302,32 +302,7 @@ akerr_ErrorContext *akgl_controller_handle_event(void *appstate, SDL_Event *even
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the movement and facing bits on the "player" actor for a D-pad or arrow press.
|
||||
*
|
||||
* A whole-application shortcut rather than a control-map binding: it looks the
|
||||
* actor up by the literal name `"player"` in #AKGL_REGISTRY_ACTOR instead of
|
||||
* being told which actor to act on, so it only ever drives one. The
|
||||
* akgl_actor_cmhf_* handlers are the general form.
|
||||
*
|
||||
* Facing follows movement unless the actor sets `movement_controls_face`, which
|
||||
* is how an actor that aims independently of the direction it walks opts out.
|
||||
*
|
||||
* Declared nowhere -- `controller.h` advertises this as
|
||||
* `akgl_controller_handle_button_down`, which does not exist. TODO.md, "Known
|
||||
* and still open" item 10.
|
||||
*
|
||||
* @param appstate Passed through from SDL. Required as a non-`NULL` token only;
|
||||
* never read.
|
||||
* @param event The button or key event. Required. Both the gamepad and
|
||||
* keyboard unions are read on every call, so the arm that does
|
||||
* not correspond to the event type is read as garbage -- which
|
||||
* works only because no real button and keycode pair collides.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p appstate or @p event is `NULL`, or if there is
|
||||
* no actor registered under the name "player".
|
||||
*/
|
||||
akerr_ErrorContext *gamepad_handle_button_down(void *appstate, SDL_Event *event)
|
||||
akerr_ErrorContext *akgl_controller_handle_button_down(void *appstate, SDL_Event *event)
|
||||
{
|
||||
akgl_Actor *player = NULL;
|
||||
|
||||
@@ -378,23 +353,7 @@ akerr_ErrorContext *gamepad_handle_button_down(void *appstate, SDL_Event *event)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the movement bit on the "player" actor for a D-pad or arrow release, and reset its animation.
|
||||
*
|
||||
* The counterpart to gamepad_handle_button_down. It clears only the movement
|
||||
* bit, leaving the facing bits alone so the actor keeps looking the way it was
|
||||
* walking, and rewinds `curSpriteFrameId` to 0 so the next step starts from the
|
||||
* first frame of the walk cycle rather than wherever it stopped.
|
||||
*
|
||||
* Declared nowhere; see gamepad_handle_button_down.
|
||||
*
|
||||
* @param appstate Passed through from SDL. Required as a non-`NULL` token only.
|
||||
* @param event The button or key release event. Required.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p appstate or @p event is `NULL`, or if there is
|
||||
* no actor registered under the name "player".
|
||||
*/
|
||||
akerr_ErrorContext *gamepad_handle_button_up(void *appstate, SDL_Event *event)
|
||||
akerr_ErrorContext *akgl_controller_handle_button_up(void *appstate, SDL_Event *event)
|
||||
{
|
||||
akgl_Actor *player = NULL;
|
||||
|
||||
@@ -433,31 +392,7 @@ akerr_ErrorContext *gamepad_handle_button_up(void *appstate, SDL_Event *event)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a gamepad that has just been plugged in, and log its mapping.
|
||||
*
|
||||
* SDL delivers no button events from an unopened gamepad, so a device that
|
||||
* appears mid-session has to be opened here the way akgl_controller_open_gamepads
|
||||
* opens the ones present at startup. A gamepad SDL has already opened is logged
|
||||
* and left alone.
|
||||
*
|
||||
* The mapping is logged because a controller with no entry in the database
|
||||
* produces no button events at all, and that is otherwise indistinguishable
|
||||
* from a broken binding.
|
||||
*
|
||||
* Declared nowhere; see gamepad_handle_button_down.
|
||||
*
|
||||
* @param appstate Passed through from SDL. Required as a non-`NULL` token only.
|
||||
* @param event The SDL_EVENT_GAMEPAD_ADDED event. Required. The joystick id
|
||||
* is read out of the `gbutton` arm rather than `gdevice`, which
|
||||
* works because the two share their `which` field.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p appstate or @p event is `NULL`.
|
||||
*
|
||||
* @note A failed `SDL_OpenGamepad` is logged rather than reported: this returns
|
||||
* success and the device stays silent.
|
||||
*/
|
||||
akerr_ErrorContext *gamepad_handle_added(void *appstate, SDL_Event *event)
|
||||
akerr_ErrorContext *akgl_controller_handle_added(void *appstate, SDL_Event *event)
|
||||
{
|
||||
SDL_JoystickID which;
|
||||
SDL_Gamepad *gamepad = NULL;
|
||||
@@ -487,22 +422,7 @@ akerr_ErrorContext *gamepad_handle_added(void *appstate, SDL_Event *event)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close a gamepad that has been unplugged.
|
||||
*
|
||||
* An unplugged device SDL still has open is a leaked handle, so this closes it.
|
||||
* A removal for a device that was never opened is logged and otherwise ignored.
|
||||
* Any control map still holding that `jsid` simply stops matching -- the map is
|
||||
* not torn down.
|
||||
*
|
||||
* Declared nowhere; see gamepad_handle_button_down.
|
||||
*
|
||||
* @param appstate Passed through from SDL. Required as a non-`NULL` token only.
|
||||
* @param event The SDL_EVENT_GAMEPAD_REMOVED event. Required.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p appstate or @p event is `NULL`.
|
||||
*/
|
||||
akerr_ErrorContext *gamepad_handle_removed(void *appstate, SDL_Event *event)
|
||||
akerr_ErrorContext *akgl_controller_handle_removed(void *appstate, SDL_Event *event)
|
||||
{
|
||||
SDL_JoystickID which;
|
||||
SDL_Gamepad *gamepad = NULL;
|
||||
@@ -521,7 +441,7 @@ akerr_ErrorContext *gamepad_handle_removed(void *appstate, SDL_Event *event)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_pushmap(int controlmapid, akgl_Control *control)
|
||||
akerr_ErrorContext *akgl_controller_pushmap(int controlmapid, akgl_Control *control)
|
||||
{
|
||||
int newmapid = 0;
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -538,7 +458,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_pushmap(int controlmapid, akg
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_default(int controlmapid, char *actorname, int kbid, int jsid)
|
||||
akerr_ErrorContext *akgl_controller_default(int controlmapid, char *actorname, int kbid, int jsid)
|
||||
{
|
||||
akgl_ControlMap *controlmap;
|
||||
akgl_Control control;
|
||||
@@ -630,7 +550,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_default(int controlmapid, cha
|
||||
} FINISH(errctx, true);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_key(int *keycode, bool *available)
|
||||
akerr_ErrorContext *akgl_controller_poll_key(int *keycode, bool *available)
|
||||
{
|
||||
akgl_Keystroke keystroke;
|
||||
|
||||
@@ -655,7 +575,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_key(int *keycode, bool *
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_keystroke(akgl_Keystroke *dest, bool *available)
|
||||
akerr_ErrorContext *akgl_controller_poll_keystroke(akgl_Keystroke *dest, bool *available)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL keystroke destination");
|
||||
@@ -666,7 +586,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_keystroke(akgl_Keystroke
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_flush_keys(void)
|
||||
akerr_ErrorContext *akgl_controller_flush_keys(void)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
keybuffer_head = 0;
|
||||
|
||||
Reference in New Issue
Block a user