Search code examples
emacsisonumber-formattingprefixes

Formatting an Integer using ISO-prefixes for kB,MB,GB,... and kiB,MiB,GiB,


I looking for the function that prints file size on the mode-line in size-indication-mode. I have searched for size-indication-mode in the source but cannot find a code-references to it. So where is the function that prints for example 22k

when file is approximately 22 kilobytes big?

What about difference between - kilobytes (kB), 1000 bytes, and - kibibytes (KiB), 1024 bytes, as defined at

Shouldn't Emacs support both?

This is of course not that hard to write but why reinvent the wheel?

http://en.wikipedia.org/wiki/Kibibyte


Solution

  • Here's the function I use.

    (defconst number-to-string-approx-suffixes
      '("k" "M" "G" "T" "P" "E" "Z" "Y"))
    (defun number-to-string-approx-suffix (n &optional binary)
      "Return an approximate decimal representation of NUMBER as a string,
    followed by a multiplier suffix (k, M, G, T, P, E, Z, Y). The representation
    is at most 5 characters long for numbers between 0 and 10^19-5*10^16.
    Uses a minus sign if negative.
    NUMBER may be an integer or a floating point number.
    If the optional argument BINARY is non-nil, use 1024 instead of 1000 as
    the base multiplier."
      (if (zerop n)
          "0"
        (let ((sign "")
              (b (if binary 1024 1000))
              (suffix "")
              (bigger-suffixes number-to-string-approx-suffixes))
          (if (< n 0)
              (setq n (- n)
                    sign "-"))
          (while (and (>= n 9999.5) (consp bigger-suffixes))
            (setq n (/ n b) ; TODO: this is rounding down; nearest would be better
                  suffix (car bigger-suffixes)
                  bigger-suffixes (cdr bigger-suffixes)))
          (concat sign
                      (if (integerp n)
                      (int-to-string n)
                    (number-to-string (floor n)))
                  suffix))))
    

    I use it in the size column of the buffer menu.

    (defvar Buffer-menu-buffer+size-shorten 'binary)
    (defadvice Buffer-menu-buffer+size (before Buffer-menu-shorten-size
                                        compile activate)
      "Shorten the size column in a buffer menu by using multiplier suffixes
    \(k, M, G, T\).
    This is done only if `Buffer-menu-buffer+size-shorten' is non-nil.
    If `Buffer-menu-buffer+size-shorten' is the symbol `binary', use binary
    multipliers (powers of 1024). Otherwise use decimal (powers of 1000)
    multipliers."
      (if Buffer-menu-buffer+size-shorten
          (let ((binary (eq Buffer-menu-buffer+size-shorten 'binary)))
            (save-match-data
              (if (string-match "^[0-9]+$" size)
                  (setq size (number-to-string-approx-suffix (string-to-number size)
                                                             binary)))))))