Skip to content

CI: Check positional printf arguments on Windows - #722

Closed
echoix wants to merge 5 commits into
mainfrom
ci-check-positional-printf-windows
Closed

echoix wants to merge 5 commits into
mainfrom
ci-check-positional-printf-windows

Conversation

@echoix

@echoix echoix commented Oct 3, 2026

Copy link
Copy Markdown
Owner

A reviewer on #720 asked whether C translation strings can use positional placeholders (%1$s, %2$s) so translators can reorder arguments. GRASS messages go through G_vasprintf() to vsnprintf, and I don't know whether that supports %N$ on Windows.

This adds a throwaway workflow that compiles a small C program with MSVC and with MSYS2 MinGW64 (with and without __USE_MINGW_ANSI_STDIO) and prints PASS/FAIL for snprintf, a vsnprintf wrapper and, on MSVC, _snprintf_p/_vsprintf_p. It does not build GRASS and is not meant to be merged upstream.

I used Claude to help write the workflow.

Comment on lines +34 to +43
#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; \

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; \

Comment on lines +55 to +68
#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"); \

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"); \

@echoix echoix closed this Oct 4, 2026
@echoix
echoix deleted the ci-check-positional-printf-windows branch October 4, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant