diff --git a/po/POTFILES.in b/po/POTFILES.in index d850dfb..39b9cc0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,6 +4,8 @@ libx52/x52_stringify.c libx52io/io_strings.c +vkm/vkm_common.c + evtest/ev_test.c joytest/x52_test.c diff --git a/po/libx52.pot b/po/libx52.pot index 9256eda..d326f6b 100644 --- a/po/libx52.pot +++ b/po/libx52.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: libx52 0.3.3\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n" -"POT-Creation-Date: 2026-03-27 08:32-0700\n" +"POT-Creation-Date: 2026-03-27 20:52-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: libx52/x52_strerror.c:23 libx52io/io_strings.c:101 +#: libx52/x52_strerror.c:23 libx52io/io_strings.c:101 vkm/vkm_common.c:25 msgid "Success" msgstr "" @@ -29,7 +29,7 @@ msgstr "" msgid "Insufficient memory" msgstr "" -#: libx52/x52_strerror.c:26 +#: libx52/x52_strerror.c:26 vkm/vkm_common.c:29 msgid "Invalid parameter" msgstr "" @@ -85,7 +85,7 @@ msgstr "" msgid "System call interrupted" msgstr "" -#: libx52/x52_strerror.c:66 libx52io/io_strings.c:125 +#: libx52/x52_strerror.c:66 libx52io/io_strings.c:125 vkm/vkm_common.c:52 #, c-format msgid "Unknown error %d" msgstr "" @@ -233,6 +233,34 @@ msgstr "" msgid "Read timeout" msgstr "" +#: vkm/vkm_common.c:26 +msgid "Unknown error" +msgstr "" + +#: vkm/vkm_common.c:27 +msgid "Not ready" +msgstr "" + +#: vkm/vkm_common.c:28 +msgid "Out of memory" +msgstr "" + +#: vkm/vkm_common.c:30 +msgid "Not supported" +msgstr "" + +#: vkm/vkm_common.c:31 +msgid "Virtual device failure" +msgstr "" + +#: vkm/vkm_common.c:32 +msgid "Unable to write event" +msgstr "" + +#: vkm/vkm_common.c:33 +msgid "No state change" +msgstr "" + #: evtest/ev_test.c:110 #, c-format msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n" diff --git a/po/xx_PL.po b/po/xx_PL.po index e555e03..b21cf17 100644 --- a/po/xx_PL.po +++ b/po/xx_PL.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: libx52 0.2.3\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n" -"POT-Creation-Date: 2026-03-27 08:32-0700\n" +"POT-Creation-Date: 2026-03-27 20:52-0700\n" "PO-Revision-Date: 2026-03-27 08:33-0700\n" "Last-Translator: Nirenjan Krishnan \n" "Language-Team: Dummy Language for testing i18n\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" -#: libx52/x52_strerror.c:23 libx52io/io_strings.c:101 +#: libx52/x52_strerror.c:23 libx52io/io_strings.c:101 vkm/vkm_common.c:25 msgid "Success" msgstr "Uccesssay" @@ -29,7 +29,7 @@ msgstr "Initializationay ailurefay" msgid "Insufficient memory" msgstr "Insufficientay emorymay" -#: libx52/x52_strerror.c:26 +#: libx52/x52_strerror.c:26 vkm/vkm_common.c:29 msgid "Invalid parameter" msgstr "Invaliday arameterpay" @@ -85,7 +85,7 @@ msgstr "Ipepay erroray" msgid "System call interrupted" msgstr "Ystemsay allcay interrupteday" -#: libx52/x52_strerror.c:66 libx52io/io_strings.c:125 +#: libx52/x52_strerror.c:66 libx52io/io_strings.c:125 vkm/vkm_common.c:52 #, c-format msgid "Unknown error %d" msgstr "Unknownay erroray %d" @@ -233,6 +233,36 @@ msgstr "I/O erroray" msgid "Read timeout" msgstr "Eadray imeouttay" +#: vkm/vkm_common.c:26 +#, fuzzy +msgid "Unknown error" +msgstr "Unknownay erroray %d" + +#: vkm/vkm_common.c:27 +msgid "Not ready" +msgstr "" + +#: vkm/vkm_common.c:28 +msgid "Out of memory" +msgstr "" + +#: vkm/vkm_common.c:30 +#, fuzzy +msgid "Not supported" +msgstr "Operationay otnay upportedsay" + +#: vkm/vkm_common.c:31 +msgid "Virtual device failure" +msgstr "" + +#: vkm/vkm_common.c:32 +msgid "Unable to write event" +msgstr "" + +#: vkm/vkm_common.c:33 +msgid "No state change" +msgstr "" + #: evtest/ev_test.c:110 #, c-format msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n" diff --git a/vkm/meson.build b/vkm/meson.build index c1fa769..95ade32 100644 --- a/vkm/meson.build +++ b/vkm/meson.build @@ -25,9 +25,19 @@ endif lib_vkm = library('vkm', vkm_files + vkm_platform_files, install: true, version: vkm_version, - dependencies: [vkm_dep], + dependencies: [vkm_dep, dep_intl], include_directories: [includes]) +vkm_strerror_test = executable('vkm-strerror-test', + 'test_strerror.c', + 'vkm_common.c', + build_by_default: false, + dependencies: [dep_cmocka, dep_intl], + include_directories: [includes], +) + +test('vkm-strerror', vkm_strerror_test, protocol: 'tap') + if host_machine.system() == 'linux' and dep_evdev.found() dep_evdev_headers = dep_evdev.partial_dependency(compile_args: true, link_args: false) vkm_linux_evdev_test = executable('vkm_linux_evdev_test', @@ -37,7 +47,7 @@ if host_machine.system() == 'linux' and dep_evdev.found() 'vkm_common.c', ), include_directories: [includes], - dependencies: [dep_cmocka, dep_evdev_headers], + dependencies: [dep_cmocka, dep_evdev_headers, dep_intl], ) test('vkm_linux_evdev', vkm_linux_evdev_test) endif diff --git a/vkm/test_strerror.c b/vkm/test_strerror.c new file mode 100644 index 0000000..946fe7c --- /dev/null +++ b/vkm/test_strerror.c @@ -0,0 +1,57 @@ +/* + * VKM — strerror unit tests + * + * Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "vkm.h" + +static void test_strerror(void **state) +{ + (void)state; + + static const char *error_map[VKM_ERROR_MAX] = { + [VKM_SUCCESS] = "Success", + [VKM_ERROR_UNKNOWN] = "Unknown error", + [VKM_ERROR_NOT_READY] = "Not ready", + [VKM_ERROR_OUT_OF_MEMORY] = "Out of memory", + [VKM_ERROR_INVALID_PARAM] = "Invalid parameter", + [VKM_ERROR_NOT_SUPPORTED] = "Not supported", + [VKM_ERROR_DEV_FAILURE] = "Virtual device failure", + [VKM_ERROR_EVENT] = "Unable to write event", + [VKM_ERROR_NO_CHANGE] = "No state change", + }; + + static const char *unknown_fmt = "Unknown error %d"; + + char expected[256]; + + for (int i = -1; i <= (int)VKM_ERROR_MAX + 1; i++) { + if (i < 0 || i >= (int)VKM_ERROR_MAX || error_map[i] == NULL) { + snprintf(expected, sizeof(expected), unknown_fmt, i); + } else { + strncpy(expected, error_map[i], sizeof(expected)); + } + assert_string_equal(expected, vkm_strerror(i)); + } +} + +static const struct CMUnitTest tests[] = { + cmocka_unit_test(test_strerror), +}; + +int main(void) +{ + cmocka_set_message_output(CM_OUTPUT_TAP); + cmocka_run_group_tests(tests, NULL, NULL); + return 0; +} diff --git a/vkm/vkm.h b/vkm/vkm.h index d40c1d5..7fb71ec 100644 --- a/vkm/vkm.h +++ b/vkm/vkm.h @@ -96,6 +96,22 @@ typedef enum { VKM_ERROR_MAX, } vkm_error_code; +/** + * @brief Return a short description for a \ref vkm_result / \ref vkm_error_code value + * + * The returned pointer refers to static storage and must not be freed. For + * unrecognized codes, the same static buffer may be overwritten by a later call. + * + * When native language support (NLS) is enabled at build time, these messages + * are translated like \ref libx52_strerror. Bind the \c libx52 text domain and + * set \c LC_MESSAGES as for other libx52 components. + * + * @param[in] code Value returned from a VKM API function + * + * @returns Pointer to a NUL-terminated description string + */ +const char *vkm_strerror(vkm_result code); + /** * @brief Option list */ diff --git a/vkm/vkm_common.c b/vkm/vkm_common.c index d01ad27..5abbbca 100644 --- a/vkm/vkm_common.c +++ b/vkm/vkm_common.c @@ -6,10 +6,54 @@ * SPDX-LicenseIdentifier: GPL-2.0-only WITH Classpath-exception-2.0 */ +#include "config.h" +#include #include +#include "gettext.h" + #include "vkm-internal.h" +#define N_(str) gettext_noop(str) +#define _(str) dgettext(PACKAGE, str) + +/* Error buffer used for building custom error strings */ +static char error_buffer[256]; + +/* List of error strings (indices must match \ref vkm_error_code) */ +static const char *error_string[] = { + N_("Success"), + N_("Unknown error"), + N_("Not ready"), + N_("Out of memory"), + N_("Invalid parameter"), + N_("Not supported"), + N_("Virtual device failure"), + N_("Unable to write event"), + N_("No state change"), +}; + +const char *vkm_strerror(vkm_result code) +{ + switch ((vkm_error_code)code) { + case VKM_SUCCESS: + case VKM_ERROR_UNKNOWN: + case VKM_ERROR_NOT_READY: + case VKM_ERROR_OUT_OF_MEMORY: + case VKM_ERROR_INVALID_PARAM: + case VKM_ERROR_NOT_SUPPORTED: + case VKM_ERROR_DEV_FAILURE: + case VKM_ERROR_EVENT: + case VKM_ERROR_NO_CHANGE: + return _(error_string[code]); + + default: + snprintf(error_buffer, sizeof(error_buffer), + _("Unknown error %d"), (int)code); + return error_buffer; + } +} + vkm_button_state _vkm_get_mouse_button_state(struct vkm_mouse_button_state *state, vkm_mouse_button button) { if (state == NULL) {