;; A handy function to display file sizes in human-readable form.
;; See http://en.wikipedia.org/wiki/Kibibyte for the reference.
-(defun file-size-human-readable (file-size &optional flavor)
+(defun file-size-human-readable (file-size &optional flavor space unit)
"Produce a string showing FILE-SIZE in human-readable form.
Optional second argument FLAVOR controls the units and the display format:
If FLAVOR is `si', each kilobyte is 1000 bytes and the produced suffixes
are \"k\", \"M\", \"G\", \"T\", etc.
If FLAVOR is `iec', each kilobyte is 1024 bytes and the produced suffixes
- are \"KiB\", \"MiB\", \"GiB\", \"TiB\", etc."
+ are \"KiB\", \"MiB\", \"GiB\", \"TiB\", etc.
+
+Optional third argument SPACE is a string put between the number and unit.
+It defaults to the empty string. We recommend a single space or
+non-breaking space, unless other constraints prohibit a space in that
+position.
+
+Optional fourth argument UNIT is the unit to use. It defaults to \"B\"
+when FLAVOR is `iec' and the empty string otherwise. We recommend \"B\"
+in all cases, since that is the standard symbol for byte."
(let ((power (if (or (null flavor) (eq flavor 'iec))
1024.0
1000.0))
- (post-fixes
- ;; none, kilo, mega, giga, tera, peta, exa, zetta, yotta
- (list "" "k" "M" "G" "T" "P" "E" "Z" "Y")))
- (while (and (>= file-size power) (cdr post-fixes))
+ (prefixes '("" "k" "M" "G" "T" "P" "E" "Z" "Y")))
+ (while (and (>= file-size power) (cdr prefixes))
(setq file-size (/ file-size power)
- post-fixes (cdr post-fixes)))
- (format (if (> (mod file-size 1.0) 0.05)
- "%.1f%s%s"
- "%.0f%s%s")
- file-size
- (if (and (eq flavor 'iec) (string= (car post-fixes) "k"))
- "K"
- (car post-fixes))
- (if (eq flavor 'iec) "iB" ""))))
+ prefixes (cdr prefixes)))
+ (let* ((prefix (car prefixes))
+ (prefixed-unit (if (eq flavor 'iec)
+ (concat
+ (if (string= prefix "k") "K" prefix)
+ (if (string= prefix "") "" "i")
+ (or unit "B"))
+ (concat prefix unit))))
+ (format (if (> (mod file-size 1.0) 0.05)
+ "%.1f%s%s"
+ "%.0f%s%s")
+ file-size
+ (if (string-empty-p prefixed-unit) "" (or space ""))
+ prefixed-unit))))
(defcustom mounted-file-systems
(if (memq system-type '(windows-nt cygwin))
(defun files--ask-user-about-large-file (size op-type filename offer-raw)
(let ((prompt (format "File %s is large (%s), really %s?"
(file-name-nondirectory filename)
- (file-size-human-readable size) op-type)))
+ (file-size-human-readable size 'iec " ") op-type)))
(if (not offer-raw)
(if (y-or-n-p prompt) nil 'abort)
(let* ((use-dialog (and (display-popup-menus-p)
exceeds the %S%% of currently available free memory (%s).
If that fails, try to open it with `find-file-literally'
\(but note that some characters might be displayed incorrectly)."
- (file-size-human-readable size)
+ (file-size-human-readable size 'iec " ")
out-of-memory-warning-percentage
- (file-size-human-readable (* total-free-memory 1024)))))))))
+ (file-size-human-readable (* total-free-memory 1024)
+ 'iec " "))))))))
(defun files--message (format &rest args)
"Like `message', except sometimes don't print to minibuffer.
(defun url-http-simple-after-change-function (_st _nd _length)
;; Function used when we do NOT know how long the document is going to be
;; Just _very_ simple 'downloaded %d' type of info.
- (url-lazy-message "Reading %s..." (file-size-human-readable (buffer-size))))
+ (url-lazy-message "Reading %s..."
+ (file-size-human-readable (buffer-size) 'iec " ")))
(defun url-http-content-length-after-change-function (_st nd _length)
"Function used when we DO know how long the document is going to be.
(url-percentage (- nd url-http-end-of-headers)
url-http-content-length)
url-http-content-type
- (file-size-human-readable (- nd url-http-end-of-headers))
- (file-size-human-readable url-http-content-length)
+ (file-size-human-readable (- nd url-http-end-of-headers) 'iec " ")
+ (file-size-human-readable url-http-content-length 'iec " ")
(url-percentage (- nd url-http-end-of-headers)
url-http-content-length))
(url-display-percentage
"Reading... %s of %s (%d%%)"
(url-percentage (- nd url-http-end-of-headers)
url-http-content-length)
- (file-size-human-readable (- nd url-http-end-of-headers))
- (file-size-human-readable url-http-content-length)
+ (file-size-human-readable (- nd url-http-end-of-headers) 'iec " ")
+ (file-size-human-readable url-http-content-length 'iec " ")
(url-percentage (- nd url-http-end-of-headers)
url-http-content-length)))
(ignore-errors (advice-remove #'write-region advice))
(ignore-errors (delete-file temp-file-name)))))
+(ert-deftest files-test-file-size-human-readable ()
+ (should (equal (file-size-human-readable 13) "13"))
+ (should (equal (file-size-human-readable 13 'si) "13"))
+ (should (equal (file-size-human-readable 13 'iec) "13B"))
+ (should (equal (file-size-human-readable 10000) "9.8k"))
+ (should (equal (file-size-human-readable 10000 'si) "10k"))
+ (should (equal (file-size-human-readable 10000 'iec) "9.8KiB"))
+ (should (equal (file-size-human-readable 4294967296 nil) "4G"))
+ (should (equal (file-size-human-readable 4294967296 'si) "4.3G"))
+ (should (equal (file-size-human-readable 4294967296 'iec) "4GiB"))
+ (should (equal (file-size-human-readable 13 nil " ") "13"))
+ (should (equal (file-size-human-readable 13 'si " ") "13"))
+ (should (equal (file-size-human-readable 13 'iec " ") "13 B"))
+ (should (equal (file-size-human-readable 10000 nil " ") "9.8 k"))
+ (should (equal (file-size-human-readable 10000 'si " ") "10 k"))
+ (should (equal (file-size-human-readable 10000 'iec " ") "9.8 KiB"))
+ (should (equal (file-size-human-readable 4294967296 nil " ") "4 G"))
+ (should (equal (file-size-human-readable 4294967296 'si " ") "4.3 G"))
+ (should (equal (file-size-human-readable 4294967296 'iec " ") "4 GiB"))
+ (should (equal (file-size-human-readable 10000 nil " " "bit") "9.8 kbit"))
+ (should (equal (file-size-human-readable 10000 'si " " "bit") "10 kbit"))
+ (should (equal (file-size-human-readable 10000 'iec " " "bit") "9.8 Kibit")))
+
(provide 'files-tests)
;;; files-tests.el ends here