diff options
-rw-r--r-- | include/slibc-human.h | 30 | ||||
-rw-r--r-- | src/slibc-human/humansize.c | 53 |
2 files changed, 53 insertions, 30 deletions
diff --git a/include/slibc-human.h b/include/slibc-human.h index 1807be6..4118625 100644 --- a/include/slibc-human.h +++ b/include/slibc-human.h @@ -231,22 +231,27 @@ int machinemode(mode_t* restrict, mode_t* restrict, const char* restrict) /** * Convert a file size of file offset from machine representation to human representation. * - * @param buffer A buffer than shall be used if it is sufficiently large. - * @param bufsize The allocation size of `buffer`. - * Must be 0 if and only if `buffer` is `NULL`. - * @param size The value to convert. - * @param mode Representation style, 0 for default. - * @param detail See documentation for the select value on `mode`. - * @param point The symbol to use for decimal points. `NULL` or empty for default. - * @return Human representation of the file size/offset, `NULL` on error. - * On success, the caller is responsible for deallocating the - * returned pointer, if and only if it is not `buffer`. + * @param buffer A buffer than shall be used if it is sufficiently large. + * @param bufsize The allocation size of `buffer`. + * Must be 0 if and only if `buffer` is `NULL`. + * @param size The value to convert. + * @param mode Representation style, 0 for default. + * @param detail See documentation for the select value on `mode`. + * @param point The symbol to use for decimal points. `NULL` or empty for default. + * @param intraspacing Spacing between values and units. `NULL` or empty for none. + * This value should depend on language and context. For English + * this value should be "" or "-", but in for example Swedish it + * should always be " ". Hence this value is a string rather than + * a booleanic integer. + * @return Human representation of the file size/offset, `NULL` on error. + * On success, the caller is responsible for deallocating the + * returned pointer, if and only if it is not `buffer`. * * @throws EINVAL If `mode` is invalid. * @throws EINVAL If `mode & HUMANSIZE_EXACT` and `detail < 0`. * @throws ENOMEM The process cannot allocate more memory. */ -char* humansize(char*, size_t, size_t, enum humansize_mode, int, const char* restrict) +char* humansize(char*, size_t, size_t, enum humansize_mode, int, const char* restrict, const char* restrict) __GCC_ONLY(__attribute__((__warn_unused_result__))); int machinesize(size_t* restrict size, const char* restrict str, enum machinesize_mode mode, @@ -254,7 +259,8 @@ int machinesize(size_t* restrict size, const char* restrict str, enum machinesiz #ifdef __C99__ -int humandur(intmax_t sec, long int nsec, const char* restrict point, const char* restrict format); +int humandur(intmax_t sec, long int nsec, const char* restrict point, const char* restrict format, + const char* restrict intraspacing, const char* restrict interspacing); int machinedur(intmax_t* restrict sec, long int* nsec, const char* restrict str, const char* restrict space, const char* restrict point); diff --git a/src/slibc-human/humansize.c b/src/slibc-human/humansize.c index 4bc94db..8bde63e 100644 --- a/src/slibc-human/humansize.c +++ b/src/slibc-human/humansize.c @@ -18,6 +18,7 @@ #include <slib-human.h> #include <stdlib.h> #include <string.h> +#include <alloca.h> #include <errno.h> @@ -25,35 +26,46 @@ /** * Convert a file size of file offset from machine representation to human representation. * - * @param buffer A buffer than shall be used if it is sufficiently large. - * @param bufsize The allocation size of `buffer`. - * Must be 0 if and only if `buffer` is `NULL`. - * @param size The value to convert. - * @param mode Representation style, 0 for default. - * @param detail See documentation for the select value on `mode`. - * @param point The symbol to use for decimal points. `NULL` or empty for default. - * @return Human representation of the file size/offset, `NULL` on error. - * On success, the caller is responsible for deallocating the - * returned pointer, if and only if it is not `buffer`. + * @param buffer A buffer than shall be used if it is sufficiently large. + * @param bufsize The allocation size of `buffer`. + * Must be 0 if and only if `buffer` is `NULL`. + * @param size The value to convert. + * @param mode Representation style, 0 for default. + * @param detail See documentation for the select value on `mode`. + * @param point The symbol to use for decimal points. `NULL` or empty for default. + * @param intraspacing Spacing between values and units. `NULL` or empty for none. + * This value should depend on language and context. For English + * this value should be "" or "-", but in for example Swedish it + * should always be " ". Hence this value is a string rather than + * a booleanic integer. + * @return Human representation of the file size/offset, `NULL` on error. + * On success, the caller is responsible for deallocating the + * returned pointer, if and only if it is not `buffer`. * * @throws EINVAL If `mode` is invalid. * @throws ENOMEM The process cannot allocate more memory. */ -char* humansize(char* buffer, size_t bufsize, size_t size, - enum humansize_mode mode, int detail, const char* restrict point) +char* humansize(char* buffer, size_t bufsize, size_t size, enum humansize_mode mode, + int detail, const char* restrict point, const char* restrict intraspacing) { +#if (__LONG_LONG_BIT > 90) && (((__LONG_LONG_BIT - 90) * 3 + 7) / 8 + 3 > 7) +# define BUFFER_SIZE (((__LONG_LONG_BIT - 90) * 3 + 7) / 8 + 3) +#else +# define BUFFER_SIZE 7 +#endif + char prefixes[] = { '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' }; size_t values[sizeof(prefixes) / sizeof(*prefixes)] = { 0 }; size_t div, i, n = 0, words = 0; char* p; char* new = NULL; -#if (__LONG_LONG_BIT > 90) && (((__LONG_LONG_BIT - 90) * 3 + 7) / 8 + 3 > 7) - char buf[((__LONG_LONG_BIT - 90) * 3 + 7) / 8 + 3]; -#else - char buf[7]; -#endif + char* buf; int m, saved_errno; + if (intraspacing == NULL) + intraspacing = ""; + buf = alloca((BUFFER_SIZE + strlen(intraspacing)) * sizeof(char)); + switch (mode & 7) { case 0: @@ -84,7 +96,7 @@ char* humansize(char* buffer, size_t bufsize, size_t size, { if (!(values[i] || (!i && !n))) break; - if (m = sprintf(buf, "%zu", values[i]), m < 0) + if (m = sprintf(buf, "%zu%s", values[i], intraspacing), m < 0) goto fail; if (i == 0) buf[m++] = 'B'; @@ -165,6 +177,11 @@ char* humansize(char* buffer, size_t bufsize, size_t size, } } } + if (*intraspacing) + { + memcpy(buffer + n, intraspacing, strlen(intraspacing) * sizeof(char)); + m += strlen(intraspacing); + } if (i == 0) buffer[n++] = 'B'; else |