Skip to content
Closed
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
129 changes: 129 additions & 0 deletions .github/scripts/positional_printf_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* Throwaway check: do POSIX positional printf arguments work here?
* Results are printed as PASS/FAIL lines; the exit status is always 0.
*
* Optional defines:
* USE_LIBINTL include <libintl.h> first and report its redirects
* TEST_LIBINTL_DIRECT also call libintl_snprintf()/libintl_vsnprintf()
*/
#ifdef USE_LIBINTL
#include <libintl.h>
#endif
#include <inttypes.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define BUFSZ 128

#ifdef TEST_LIBINTL_DIRECT
/* Declared here in case libintl.h only declares them conditionally. */
extern int libintl_snprintf(char *, size_t, const char *, ...);
extern int libintl_vsnprintf(char *, size_t, const char *, va_list);
#endif

static void report(const char *func, const char *fmt, const char *result,
const char *expected)
{
printf("%s: func=%s format=\"%s\" result=\"%s\" expected=\"%s\"\n",
strcmp(result, expected) == 0 ? "PASS" : "FAIL", func, fmt, result,
expected);
}

/* Mimics G_vasprintf(): formats through a va_list function. */
#define DEFINE_WRAPPER(name, vfunc) \
static int name(char *buf, size_t n, const char *fmt, ...) \
{ \
va_list ap; \
int ret; \
\
va_start(ap, fmt); \
ret = vfunc(buf, n, fmt, ap); \
va_end(ap); \
return ret; \
Comment on lines +34 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pre-commit] reported by reviewdog 🐶

Suggested change
#define DEFINE_WRAPPER(name, vfunc) \
static int name(char *buf, size_t n, const char *fmt, ...) \
{ \
va_list ap; \
int ret; \
\
va_start(ap, fmt); \
ret = vfunc(buf, n, fmt, ap); \
va_end(ap); \
return ret; \
#define DEFINE_WRAPPER(name, vfunc) \
static int name(char *buf, size_t n, const char *fmt, ...) \
{ \
va_list ap; \
int ret; \
\
va_start(ap, fmt); \
ret = vfunc(buf, n, fmt, ap); \
va_end(ap); \
return ret; \

}

DEFINE_WRAPPER(wrap_vsnprintf, vsnprintf)
#ifdef TEST_LIBINTL_DIRECT
DEFINE_WRAPPER(wrap_libintl_vsnprintf, libintl_vsnprintf)
#endif
#ifdef _MSC_VER
DEFINE_WRAPPER(wrap_vsprintf_p, _vsprintf_p)
#endif

/* Runs all formats through fn(buf, size, fmt, args...). */
#define RUN_CASES(label, fn) \
do { \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$s %1$s", "a", "b"); \
report(label, "%2$s %1$s", buf, "b a"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$d %1$s", "x", 42); \
report(label, "%2$d %1$s", buf, "42 x"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$lu %1$llu", 5ULL, 7UL); \
report(label, "%2$lu %1$llu", buf, "7 5"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$" PRIu64 " %1$s", "x", (uint64_t)123); \
report(label, "%2$" PRIu64 " %1$s", buf, "123 x"); \
Comment on lines +55 to +68

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pre-commit] reported by reviewdog 🐶

Suggested change
#define RUN_CASES(label, fn) \
do { \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$s %1$s", "a", "b"); \
report(label, "%2$s %1$s", buf, "b a"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$d %1$s", "x", 42); \
report(label, "%2$d %1$s", buf, "42 x"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$lu %1$llu", 5ULL, 7UL); \
report(label, "%2$lu %1$llu", buf, "7 5"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$" PRIu64 " %1$s", "x", (uint64_t)123); \
report(label, "%2$" PRIu64 " %1$s", buf, "123 x"); \
#define RUN_CASES(label, fn) \
do { \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$s %1$s", "a", "b"); \
report(label, "%2$s %1$s", buf, "b a"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$d %1$s", "x", 42); \
report(label, "%2$d %1$s", buf, "42 x"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$lu %1$llu", 5ULL, 7UL); \
report(label, "%2$lu %1$llu", buf, "7 5"); \
memset(buf, 0, sizeof buf); \
fn(buf, sizeof buf, "%2$" PRIu64 " %1$s", "x", (uint64_t)123); \
report(label, "%2$" PRIu64 " %1$s", buf, "123 x"); \

} while (0)

int main(void)
{
char buf[BUFSZ];

#ifdef _MSC_VER
printf("compiler: MSVC _MSC_VER=%d\n", _MSC_VER);
#endif
#ifdef __GNUC__
printf("compiler: GCC %d.%d\n", __GNUC__, __GNUC_MINOR__);
#endif
#ifdef _UCRT
printf("runtime: _UCRT defined\n");
#else
printf("runtime: _UCRT not defined\n");
#endif
#ifdef __USE_MINGW_ANSI_STDIO
printf("__USE_MINGW_ANSI_STDIO=%d\n", __USE_MINGW_ANSI_STDIO);
#else
printf("__USE_MINGW_ANSI_STDIO not defined\n");
#endif
#ifdef USE_LIBINTL
printf("libintl.h included first\n");
#ifdef snprintf
printf("snprintf IS a macro after libintl.h\n");
#else
printf("snprintf is NOT a macro after libintl.h\n");
#endif
#ifdef vsnprintf
printf("vsnprintf IS a macro after libintl.h\n");
#else
printf("vsnprintf is NOT a macro after libintl.h\n");
#endif
#ifdef _INTL_REDIRECT_MACROS
printf("_INTL_REDIRECT_MACROS is defined\n");
#else
printf("_INTL_REDIRECT_MACROS is not defined\n");
#endif
#ifdef _INTL_NO_REDIRECT_PRINTF
printf("_INTL_NO_REDIRECT_PRINTF is defined\n");
#else
printf("_INTL_NO_REDIRECT_PRINTF is not defined\n");
#endif
#endif

RUN_CASES("snprintf", snprintf);
RUN_CASES("vsnprintf(wrapper)", wrap_vsnprintf);

#ifdef TEST_LIBINTL_DIRECT
RUN_CASES("libintl_snprintf", libintl_snprintf);
RUN_CASES("libintl_vsnprintf(wrapper)", wrap_libintl_vsnprintf);
#endif

#ifdef _MSC_VER
RUN_CASES("_sprintf_p", _sprintf_p);
RUN_CASES("_vsprintf_p(wrapper)", wrap_vsprintf_p);
#endif

return 0;
}
91 changes: 91 additions & 0 deletions .github/workflows/positional_printf_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: Positional printf check

# Throwaway check of POSIX positional printf arguments on Windows toolchains.
on:
workflow_dispatch:
pull_request:
paths:
- .github/workflows/positional_printf_check.yml
- .github/scripts/positional_printf_check.c

permissions: {}

jobs:
msvc:
name: MSVC
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: ilammy/msvc-dev-cmd@a102174a2b586eec2ea151a69e6fd14404a8ce7c # v1.13.0
- name: Compile
shell: cmd
run: cl /nologo /W3 .github\scripts\positional_printf_check.c /Fe:check.exe
- name: Run
shell: cmd
run: check.exe
- name: Install libintl with vcpkg
id: vcpkg
continue-on-error: true
shell: cmd
run: vcpkg install gettext-libintl:x64-windows
- name: Compile with libintl
if: steps.vcpkg.outcome == 'success'
continue-on-error: true
shell: cmd
run: |
set VPREFIX=%VCPKG_INSTALLATION_ROOT%\installed\x64-windows
dir %VPREFIX%\include\libintl.h %VPREFIX%\lib\*intl* %VPREFIX%\bin\*intl*
findstr /n /i "define.*printf _INTL_REDIRECT" %VPREFIX%\include\libintl.h
dumpbin /exports %VPREFIX%\bin\intl-8.dll | findstr /i "printf"
cl /nologo /W3 /DUSE_LIBINTL /I%VPREFIX%\include .github\scripts\positional_printf_check.c /Fe:check_intl.exe /link /LIBPATH:%VPREFIX%\lib intl.lib
cl /nologo /W3 /DUSE_LIBINTL /DTEST_LIBINTL_DIRECT /I%VPREFIX%\include .github\scripts\positional_printf_check.c /Fe:check_intl_direct.exe /link /LIBPATH:%VPREFIX%\lib intl.lib
- name: Run with libintl
if: steps.vcpkg.outcome == 'success'
continue-on-error: true
shell: cmd
run: |
set PATH=%VCPKG_INSTALLATION_ROOT%\installed\x64-windows\bin;%PATH%
check_intl.exe

mingw:
name: MinGW64 (MSYS2)
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: msys2/setup-msys2@ec48f7c5447b3140e2b088413ae3a55687bccb6e # v2.33.0
with:
msystem: MINGW64
update: false
install: >-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-gettext-runtime
mingw-w64-x86_64-gettext-tools
- name: Compile
run: |
gcc -Wall -DUSE_LIBINTL -DTEST_LIBINTL_DIRECT -o check_intl.exe .github/scripts/positional_printf_check.c -lintl
gcc -Wall -D__USE_MINGW_ANSI_STDIO=0 -DUSE_LIBINTL -DTEST_LIBINTL_DIRECT -o check_intl_msvcrt.exe .github/scripts/positional_printf_check.c -lintl
gcc -Wall -o check_default.exe .github/scripts/positional_printf_check.c
gcc -Wall -D__USE_MINGW_ANSI_STDIO=1 -o check_ansi.exe .github/scripts/positional_printf_check.c
gcc -Wall -D__USE_MINGW_ANSI_STDIO=0 -o check_msvcrt.exe .github/scripts/positional_printf_check.c
- name: Run with default __USE_MINGW_ANSI_STDIO
run: ./check_default.exe
- name: Run with __USE_MINGW_ANSI_STDIO=1
run: ./check_ansi.exe
- name: Run with __USE_MINGW_ANSI_STDIO=0
run: ./check_msvcrt.exe
- name: Show libintl.h printf redirects
run: |
ls -l /mingw64/include/libintl.h
grep -n -i "define.*printf\|_INTL_REDIRECT\|_INTL_NO_REDIRECT" /mingw64/include/libintl.h
- name: Run with libintl.h
run: ./check_intl.exe
- name: Run with libintl.h and __USE_MINGW_ANSI_STDIO=0
run: ./check_intl_msvcrt.exe
Loading