On Windows, vsnprintf deviates in two regards from the "usual" behavior that its callers in GIT expect: - It returns -1 if the buffer is too small instead of the number of characters that the operation produces. - The size parameter is the number of characters to write, which does not include the trailing NUL byte, instead of the available space. This wrapper computes the needed buffer size by trying various sizes with exponential growth. A large growth factor is used so as only few trials are required if a really large result needs to be stored. Signed-off-by: Johannes Sixt <johannes.sixt@xxxxxxxxxx> --- compat/mingw.c | 34 ++++++++++++++++++++++++++++++++++ git-compat-util.h | 3 +++ 2 files changed, 37 insertions(+), 0 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4888a03..77e4b83 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -115,6 +115,40 @@ int mingw_rename(const char *pold, const char *pnew) return -1; } +#undef vsnprintf +/* Note that the size parameter specifies the available space, i.e. + * includes the trailing NUL byte; but Windows's vsnprintf expects the + * number of characters to write without the trailing NUL. + */ + +/* This is out of line because it uses alloca() behind the scenes, + * which must not be called in a loop (alloca() reclaims the allocations + * only at function exit). + */ +static int try_vsnprintf(size_t size, const char *fmt, va_list args) +{ + char buf[size]; /* gcc-ism */ + return vsnprintf(buf, size-1, fmt, args); +} + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int len; + if (size > 0) { + len = vsnprintf(buf, size-1, fmt, args); + if (len >= 0) + return len; + } + /* ouch, buffer too small; need to compute the size */ + if (size < 250) + size = 250; + do { + size *= 4; + len = try_vsnprintf(size, fmt, args); + } while (len < 0); + return len; +} + struct passwd *getpwuid(int uid) { static char user_name[100]; diff --git a/git-compat-util.h b/git-compat-util.h index 483ace2..6fa93b6 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -602,6 +602,9 @@ char *mingw_getcwd(char *pointer, int len); int mingw_rename(const char*, const char*); #define rename mingw_rename +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +#define vsnprintf mingw_vsnprintf + sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal -- 1.5.4.1.126.ge5a7d - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html