mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
Change GLib size units policy
This commit changes GLib size units policy. We now prefer SI units and allow for use of proper IEC units where desired. g_format_size_for_display() which incorrectly mixed IEC units with SI suffixes is left unmodified, but has been deprecated. g_format_size() has been introduced which uses SI units and suffixes. g_format_size_full() has also been added which takes a flags argument to allow for use of IEC units (with correct suffixes). It also allows for a "long format" output which includes the total number of bytes. For example: "238.5 MB (238,472,938 bytes)".
This commit is contained in:
parent
90cccf14b2
commit
afd1e36970
@ -1651,6 +1651,11 @@ g_build_filename
|
||||
g_build_filenamev
|
||||
g_build_path
|
||||
g_build_pathv
|
||||
|
||||
<SUBSECTION>
|
||||
g_format_size
|
||||
GFormatSizeFlags
|
||||
g_format_size_full
|
||||
g_format_size_for_display
|
||||
|
||||
<SUBSECTION>
|
||||
|
@ -1767,6 +1767,13 @@ g_build_filename (const gchar *first_element,
|
||||
return str;
|
||||
}
|
||||
|
||||
#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000))
|
||||
#define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
#define EXABYTE_FACTOR (PETABYTE_FACTOR * KILOBYTE_FACTOR)
|
||||
|
||||
#define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
|
||||
#define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
@ -1774,6 +1781,189 @@ g_build_filename (const gchar *first_element,
|
||||
#define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
#define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
||||
|
||||
/**
|
||||
* g_format_size:
|
||||
* @size: a size in bytes
|
||||
*
|
||||
* Formats a size (for example the size of a file) into a human readable
|
||||
* string. Sizes are rounded to the nearest size prefix (kB, MB, GB)
|
||||
* and are displayed rounded to the nearest tenth. E.g. the file size
|
||||
* 3292528 bytes will be converted into the string "3.2 MB".
|
||||
*
|
||||
* The prefix units base is 1000 (i.e. 1 kB is 1000 bytes).
|
||||
*
|
||||
* This string should be freed with g_free() when not needed any longer.
|
||||
*
|
||||
* See g_format_size_full() for more options about how the size might be
|
||||
* formatted.
|
||||
*
|
||||
* Returns: a newly-allocated formatted string containing a human readable
|
||||
* file size.
|
||||
*
|
||||
* Since: 2.30
|
||||
**/
|
||||
gchar *
|
||||
g_format_size (guint64 size)
|
||||
{
|
||||
return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_format_size_full:
|
||||
* @size: a size in bytes
|
||||
* @flags: #GFormatSizeFlags to modify the output
|
||||
*
|
||||
* Formats a size.
|
||||
*
|
||||
* This function is similar to g_format_size() but allows for flags that
|
||||
* modify the output. See #GFormatSizeFlags.
|
||||
*
|
||||
* Returns: a newly-allocated formatted string containing a human
|
||||
* readable file size.
|
||||
*
|
||||
* Since: 2.30
|
||||
**/
|
||||
/**
|
||||
* GFormatSizeFlags:
|
||||
* @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size()
|
||||
* @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style
|
||||
* suffixes. IEC units should only be used
|
||||
* for reporting things with a strong "power
|
||||
* of 2" basis, like RAM sizes or RAID stripe
|
||||
* sizes. Network and storage sizes should
|
||||
* be reported in the normal SI units.
|
||||
* @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part
|
||||
* of the returned string. For example,
|
||||
* "45.6 kB (45,612 bytes)".
|
||||
*
|
||||
* Flags to modify the format of the string returned by
|
||||
* g_format_size_full().
|
||||
**/
|
||||
gchar *
|
||||
g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags)
|
||||
{
|
||||
/* Longest possibility for (2^64 - 1) is 42 characters:
|
||||
*
|
||||
* "16.0 EB (18 446 744 073 709 551 615 bytes)"
|
||||
*/
|
||||
gchar buffer[80];
|
||||
gsize i;
|
||||
|
||||
if (flags & G_FORMAT_SIZE_IEC_UNITS)
|
||||
{
|
||||
if (size < KIBIBYTE_FACTOR)
|
||||
{
|
||||
i = snprintf (buffer, sizeof buffer,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEBIBYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR);
|
||||
|
||||
else if (size < GIBIBYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < TEBIBYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR);
|
||||
|
||||
else if (size < PEBIBYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR);
|
||||
|
||||
else if (size < EXBIBYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR);
|
||||
|
||||
else
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size < KILOBYTE_FACTOR)
|
||||
{
|
||||
i = snprintf (buffer, sizeof buffer,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
||||
(guint) size);
|
||||
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
||||
}
|
||||
|
||||
else if (size < MEGABYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR);
|
||||
|
||||
else if (size < GIGABYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR);
|
||||
|
||||
else if (size < TERABYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR);
|
||||
|
||||
else if (size < PETABYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR);
|
||||
|
||||
else if (size < EXABYTE_FACTOR)
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR);
|
||||
|
||||
else
|
||||
i = snprintf (buffer, sizeof buffer, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR);
|
||||
}
|
||||
|
||||
if (flags & G_FORMAT_SIZE_LONG_FORMAT)
|
||||
{
|
||||
buffer[i++] = ' ';
|
||||
buffer[i++] = '(';
|
||||
|
||||
/* First problem: we need to use the number of bytes to decide on
|
||||
* the plural form that is used for display, but the number of
|
||||
* bytes potentially exceeds the size of a guint (which is what
|
||||
* ngettext() takes).
|
||||
*
|
||||
* From a pragmatic standpoint, it seems that all known languages
|
||||
* base plural forms on one or both of the following:
|
||||
*
|
||||
* - the lowest digits of the number
|
||||
*
|
||||
* - if the number if greater than some small value
|
||||
*
|
||||
* Here's how we fake it: Draw an arbitrary line at one thousand.
|
||||
* If the number is below that, then fine. If it is above it,
|
||||
* then we take the modulus of the number by one thousand (in
|
||||
* order to keep the lowest digits) and add one thousand to that
|
||||
* (in order to ensure that 1001 is not treated the same as 1).
|
||||
*/
|
||||
guint plural_form = size < 1000 ? size : size % 1000 + 1000;
|
||||
|
||||
/* Second problem: we need to translate the string "%u byte" and
|
||||
* "%u bytes" for pluralisation, but the correct number format to
|
||||
* use for a gsize is different depending on which architecture
|
||||
* we're on.
|
||||
*
|
||||
* Solution: format the number separately and use "%s bytes" on
|
||||
* all platforms.
|
||||
*/
|
||||
gchar formatted_number[40];
|
||||
gint j;
|
||||
|
||||
/* The "'" modifier is not available on Windows, so we'd better
|
||||
* use g_snprintf().
|
||||
*/
|
||||
j = g_snprintf (formatted_number, sizeof formatted_number,
|
||||
"%'"G_GUINT64_FORMAT, size);
|
||||
g_assert (j < sizeof formatted_number);
|
||||
|
||||
/* Extra paranoia... */
|
||||
g_assert (i < sizeof buffer - 10);
|
||||
i += snprintf (buffer + i, sizeof buffer - i,
|
||||
g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", plural_form),
|
||||
formatted_number);
|
||||
g_assert (i < sizeof buffer - 10);
|
||||
buffer[i++] = ')';
|
||||
}
|
||||
|
||||
buffer[i++] = '\0';
|
||||
|
||||
return g_memdup (buffer, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_format_size_for_display:
|
||||
* @size: a size in bytes.
|
||||
@ -1790,6 +1980,9 @@ g_build_filename (const gchar *first_element,
|
||||
* Returns: a newly-allocated formatted string containing a human readable
|
||||
* file size.
|
||||
*
|
||||
* Deprecated:2.30: This function is broken due to its use of SI
|
||||
* suffixes to denote IEC units. Use g_format_size()
|
||||
* instead.
|
||||
* Since: 2.16
|
||||
**/
|
||||
char *
|
||||
|
@ -110,7 +110,20 @@ gint g_file_open_tmp (const gchar *tmpl,
|
||||
gchar **name_used,
|
||||
GError **error);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_FORMAT_SIZE_DEFAULT,
|
||||
G_FORMAT_SIZE_IEC_UNITS,
|
||||
G_FORMAT_SIZE_LONG_FORMAT
|
||||
} GFormatSizeFlags;
|
||||
|
||||
char * g_format_size_full (guint64 size,
|
||||
GFormatSizeFlags flags);
|
||||
char * g_format_size (guint64 size);
|
||||
|
||||
#ifndef G_DISABLE_DEPRECATED
|
||||
char *g_format_size_for_display (goffset size);
|
||||
#endif
|
||||
|
||||
gchar *g_build_path (const gchar *separator,
|
||||
const gchar *first_element,
|
||||
|
@ -346,6 +346,8 @@ g_file_open_tmp PRIVATE
|
||||
g_file_test PRIVATE
|
||||
#endif
|
||||
g_file_read_link
|
||||
g_format_size
|
||||
g_format_size_full
|
||||
g_format_size_for_display
|
||||
#ifndef _WIN64
|
||||
g_mkstemp PRIVATE
|
||||
|
@ -483,12 +483,24 @@ test_mkdir_with_parents (void)
|
||||
static void
|
||||
test_format_size_for_display (void)
|
||||
{
|
||||
/* nobody called setlocale(), so we should get "C" behaviour... */
|
||||
check_string (g_format_size_for_display (0), "0 bytes");
|
||||
check_string (g_format_size_for_display (1), "1 byte");
|
||||
check_string (g_format_size_for_display (2), "2 bytes");
|
||||
check_string (g_format_size_for_display (1024), "1.0 KB");
|
||||
check_string (g_format_size_for_display (1024 * 1024), "1.0 MB");
|
||||
check_string (g_format_size_for_display (1024 * 1024 * 1024), "1.0 GB");
|
||||
|
||||
check_string (g_format_size (0), "0 bytes");
|
||||
check_string (g_format_size (1), "1 byte");
|
||||
check_string (g_format_size (2), "2 bytes");
|
||||
check_string (g_format_size (1000), "1.0 kB");
|
||||
check_string (g_format_size (1000 * 1000), "1.0 MB");
|
||||
check_string (g_format_size (1000 * 1000 * 1000), "1.0 GB");
|
||||
|
||||
check_string (g_format_size_full (238472938, G_FORMAT_SIZE_IEC_UNITS), "227.4 MiB");
|
||||
check_string (g_format_size_full (238472938, G_FORMAT_SIZE_DEFAULT), "238.5 MB");
|
||||
check_string (g_format_size_full (238472938, G_FORMAT_SIZE_LONG_FORMAT), "238.5 MB (238472938 bytes)");
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user