Author: brane Date: Sun Nov 25 17:30:17 2018 New Revision: 1847422 URL: http://svn.apache.org/viewvc?rev=1847422&view=rev Log: Follow up to r1847384, changing the 'svn ls -vH' output to:
- fix a bug where the size is between 1000 and 1023 units; and, - use the locale-specific decimal separator. * subversion/svn/list-cmd.c: Include <assert.h> for assert(), <math.h> for fabs() and <stdio.h> for sprintf(). (get_human_readable_size): - Update the part of the docstring about negative sizes. - Scale to the next higher magnitude when the adjusted size is between 1000 and 1023 units. - Use standard sprintf() to format the displayed number, because APR's formatter does not use locale information. Modified: subversion/trunk/subversion/svn/list-cmd.c Modified: subversion/trunk/subversion/svn/list-cmd.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/list-cmd.c?rev=1847422&r1=1847421&r2=1847422&view=diff ============================================================================== --- subversion/trunk/subversion/svn/list-cmd.c (original) +++ subversion/trunk/subversion/svn/list-cmd.c Sun Nov 25 17:30:17 2018 @@ -21,6 +21,10 @@ * ==================================================================== */ +#include <assert.h> +#include <math.h> +#include <stdio.h> + #include "svn_cmdline.h" #include "svn_client.h" #include "svn_error.h" @@ -71,7 +75,8 @@ static const apr_uint32_t print_dirent_f SVN_DIRENT_CREATED_REV | SVN_DIRENT_LAST_AUTHOR); /* Converts a file size to human-readable form with base-2 unit suffix. - File sizes are never negative, so we don't handle that case. */ + File sizes are never negative, so we don't handle that case other than + making sure that the scale adjustment will work. */ static const char * get_human_readable_size(svn_filesize_t size, apr_pool_t *scratch_pool) { @@ -90,13 +95,14 @@ get_human_readable_size(svn_filesize_t s {APR_INT64_C(0x0003FFFFFFFFFFFF), 'E'}, /* exbi */ {APR_INT64_C(0x0FFFFFFFFFFFFFFF), 'P'} /* pibi */ }; + static const apr_size_t order_size = sizeof(order) / sizeof(order[0]); const svn_filesize_t abs_size = ((size < 0) ? -size : size); double human_readable_size; /* Find the size mask for the (absolute) file size. It would be sexy to do a binary search here, but with only 7 elements in the array ... */ - apr_size_t index = sizeof(order) / sizeof(order[0]); + apr_size_t index = order_size; while (index > 0) { --index; @@ -111,15 +117,41 @@ get_human_readable_size(svn_filesize_t s shift by (index * 10) bits. But we split it into an integer and a floating-point division, so that we don't overflow the mantissa at very large file sizes. */ + ; + if ((abs_size >> 10 * index) > 999) + { + /* This assertion should never fail, because we only have 4 binary + digits in the petabyte range and so the number of petabytes can't + be large enough to enter this conditional block. */ + assert(index < order_size - 1); + ++index; + } human_readable_size = (index == 0 ? (double)size : (size >> 3 * index) / 128.0 / index); - /* When the absolute adjusted size is < 10, show tenths of a unit, too. - NOTE: This *should* display the locale-specific decimal separator, - but apparently APR isn't too hot on localisation. */ - return apr_psprintf(scratch_pool, "%.*f%c", - (abs_size >> 10 * index < 10) ? 1 : 0, - human_readable_size, order[index].suffix); + /* NOTE: We want to display a locale-specific decimal sepratator, but + APR's formatter completely ignores the locale. So we use the + good, old, standard, *dangerous* sprintf() to format the size. + + But, on the brigt side, we've just made sure that the number has + no more than 3 non-fractional digits. So the call to sprintf() + here should be safe. */ + { + /* 3 digits (or 2 digits and 1 decimal separator) + + 1 unit suffix + + 1 negative sign (which should not appear under normal circumstances) + + 1 nul terminator + --- + = 6 characters of space needed in the buffer. */ + char buffer[8]; + + /* When the adjusted size has only one significant digit left of the + decimal point, show tenths of a unit, too. */ + sprintf(buffer, "%.*f%c", + fabs(human_readable_size) < 10.0 ? 1 : 0, + human_readable_size, order[index].suffix); + return apr_pstrdup(scratch_pool, buffer); + } } /* This implements the svn_client_list_func2_t API, printing a single