Change order of GFormatSizeFlags
[platform/upstream/glib.git] / glib / gfileutils.c
index c0e95c0..fc101bd 100644 (file)
@@ -963,6 +963,7 @@ write_to_temp_file (const gchar  *contents,
                   display_name, 
                   g_strerror (save_errno));
 
+      fclose (file);
       g_unlink (tmp_name);
       
       goto out;
@@ -1006,6 +1007,7 @@ write_to_temp_file (const gchar  *contents,
                     display_name,
                     g_strerror (save_errno));
 
+        fclose (file);
        g_unlink (tmp_name);
 
        goto out;
@@ -1026,6 +1028,7 @@ write_to_temp_file (const gchar  *contents,
                   display_name, 
                   g_strerror (save_errno));
 
+      fclose (file);
       g_unlink (tmp_name);
       
       goto out;
@@ -1506,7 +1509,7 @@ g_build_path_va (const gchar  *separator,
 /**
  * g_build_pathv:
  * @separator: a string used to separator the elements of the path.
- * @args: %NULL-terminated array of strings containing the path elements.
+ * @args: (array zero-terminated=1): %NULL-terminated array of strings containing the path elements.
  * 
  * Behaves exactly like g_build_path(), but takes the path elements 
  * as a string array, instead of varargs. This function is mainly
@@ -1764,13 +1767,190 @@ g_build_filename (const gchar *first_element,
   return str;
 }
 
-#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
+#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)
+#define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
+#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_LONG_FORMAT: include the exact number of bytes as part
+ *                             of the returned string.  For example,
+ *                             "45.6 kB (45,612 bytes)".
+ * @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.
+ *
+ * Flags to modify the format of the string returned by
+ * g_format_size_full().
+ **/
+gchar *
+g_format_size_full (guint64          size,
+                    GFormatSizeFlags flags)
+{
+  GString *string;
+
+  string = g_string_new (NULL);
+
+  if (flags & G_FORMAT_SIZE_IEC_UNITS)
+    {
+      if (size < KIBIBYTE_FACTOR)
+        {
+          g_string_printf (string,
+                           g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
+                           (guint) size);
+          flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
+        }
+
+      else if (size < MEBIBYTE_FACTOR)
+        g_string_printf (string, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR);
+
+      else if (size < GIBIBYTE_FACTOR)
+        g_string_printf (string, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR);
+
+      else if (size < TEBIBYTE_FACTOR)
+        g_string_printf (string, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR);
+
+      else if (size < PEBIBYTE_FACTOR)
+        g_string_printf (string, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR);
+
+      else if (size < EXBIBYTE_FACTOR)
+        g_string_printf (string, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR);
+
+      else
+        g_string_printf (string, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR);
+    }
+  else
+    {
+      if (size < KILOBYTE_FACTOR)
+        {
+          g_string_printf (string,
+                           g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
+                           (guint) size);
+          flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
+        }
+
+      else if (size < MEGABYTE_FACTOR)
+        g_string_printf (string, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR);
+
+      else if (size < GIGABYTE_FACTOR)
+        g_string_printf (string, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR);
+
+      else if (size < TERABYTE_FACTOR)
+        g_string_printf (string, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR);
+
+      else if (size < PETABYTE_FACTOR)
+        g_string_printf (string, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR);
+
+      else if (size < EXABYTE_FACTOR)
+        g_string_printf (string, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR);
+
+      else
+        g_string_printf (string, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR);
+    }
+
+  if (flags & G_FORMAT_SIZE_LONG_FORMAT)
+    {
+      /* 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.
+       */
+      const gchar *translated_format;
+      GString *formatted_number;
+
+      /* Translators: the %s in "%s bytes" will always be replaced by a number. */
+      translated_format = g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", plural_form);
+
+      formatted_number = g_string_new (NULL);
+      g_string_printf (formatted_number, "%'"G_GUINT64_FORMAT, size);
+      g_string_append (string, " (");
+      g_string_append_printf (string, translated_format, formatted_number->str);
+      g_string_free (formatted_number, TRUE);
+      g_string_append (string, ")");
+    }
+
+  return g_string_free (string, FALSE);
+}
+
 /**
  * g_format_size_for_display:
  * @size: a size in bytes.
@@ -1787,45 +1967,48 @@ 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 *
 g_format_size_for_display (goffset size)
 {
-  if (size < (goffset) KILOBYTE_FACTOR)
+  if (size < (goffset) KIBIBYTE_FACTOR)
     return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
   else
     {
       gdouble displayed_size;
       
-      if (size < (goffset) MEGABYTE_FACTOR)
+      if (size < (goffset) MEBIBYTE_FACTOR)
        {
-         displayed_size = (gdouble) size / (gdouble) KILOBYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f KB"), displayed_size);
        }
-      else if (size < (goffset) GIGABYTE_FACTOR)
+      else if (size < (goffset) GIBIBYTE_FACTOR)
        {
-         displayed_size = (gdouble) size / (gdouble) MEGABYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f MB"), displayed_size);
        }
-      else if (size < (goffset) TERABYTE_FACTOR)
+      else if (size < (goffset) TEBIBYTE_FACTOR)
        {
-         displayed_size = (gdouble) size / (gdouble) GIGABYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f GB"), displayed_size);
        }
-      else if (size < (goffset) PETABYTE_FACTOR)
+      else if (size < (goffset) PEBIBYTE_FACTOR)
        {
-         displayed_size = (gdouble) size / (gdouble) TERABYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f TB"), displayed_size);
        }
-      else if (size < (goffset) EXABYTE_FACTOR)
+      else if (size < (goffset) EXBIBYTE_FACTOR)
        {
-         displayed_size = (gdouble) size / (gdouble) PETABYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f PB"), displayed_size);
        }
       else
         {
-         displayed_size = (gdouble) size / (gdouble) EXABYTE_FACTOR;
+         displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR;
          return g_strdup_printf (_("%.1f EB"), displayed_size);
         }
     }