The patch for APR trunk * supposedly fixes bugs interpreting the apr_snprintf() retcode on Windows (untested) * adds a test for short input buffer (tested on Unix, anticipated different retcode on Windows supposedly handled) * adds weasel words to the apr_strftime() documentation since Windows has had different possibilities on what happens to a short input buffer (either whatever strftime() does on overflow or what the extra-strftime function does on overflow)
Does anyone want to try it on Windows and/or eyeball it? For 2.0, we can pick a specific behavior to use in all platforms*cases.
Index: time/win32/timestr.c =================================================================== --- time/win32/timestr.c (revision 1078737) +++ time/win32/timestr.c (working copy) @@ -124,6 +124,7 @@ #ifndef _WIN32_WCE +/* Handle extra format strings which aren't supported by Win32 strftime() */ apr_size_t win32_strftime_extra(char *s, size_t max, const char *format, const struct tm *tm) { @@ -142,9 +143,10 @@ } switch (format[i+1]) { case 'C': + /* requirement, met by for-loop condition: max > j */ length_written = apr_snprintf(new_format + j, max - j, "%2d", (tm->tm_year + 1970)/100); - j = (length_written == -1) ? max : (j + length_written); + j = (length_written != 2) ? max : (j + length_written); i += 2; break; case 'D': @@ -170,9 +172,10 @@ j += 8; break; case 'e': + /* requirement, met by for-loop condition: max > j */ length_written = apr_snprintf(new_format + j, max - j, "%2d", tm->tm_mday); - j = (length_written == -1) ? max : (j + length_written); + j = (length_written != 2) ? max : (j + length_written); i += 2; break; default: Index: test/testtime.c =================================================================== --- test/testtime.c (revision 1078737) +++ test/testtime.c (working copy) @@ -227,6 +227,22 @@ ABTS_STR_EQUAL(tc, "19:05:36", str); } +static void test_strftimesmallbuffer(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + char str[STR_SIZE]; + apr_size_t sz; + + rv = apr_time_exp_gmt(&xt, now); + rv = apr_strftime(str, &sz, 1, "%C", &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_strftime"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_TRUE(tc, sz == 1 || sz == 0); +} + static void test_exp_tz(abts_case *tc, void *data) { apr_status_t rv; @@ -297,6 +313,7 @@ abts_run_test(suite, test_ctime, NULL); abts_run_test(suite, test_strftime, NULL); abts_run_test(suite, test_strftimesmall, NULL); + abts_run_test(suite, test_strftimesmallbuffer, NULL); abts_run_test(suite, test_exp_tz, NULL); abts_run_test(suite, test_strftimeoffset, NULL); abts_run_test(suite, test_2038, NULL); Index: include/apr_time.h =================================================================== --- include/apr_time.h (revision 1078737) +++ include/apr_time.h (working copy) @@ -209,7 +209,9 @@ /** * formats the exploded time according to the format specified * @param s string to write to - * @param retsize The length of the returned string + * @param retsize The number of characters stored, not including terminating + * '\0'; if the buffer is insufficient, a partial string may or may not be + * stored. * @param max The maximum length of the string * @param format The format for the time string * @param tm The time to convert