From a831bdf5b3571284ffa4efb69e506f09403ab240 Mon Sep 17 00:00:00 2001
From: Michael Osipov <1983-01-06@gmx.net>
Date: Thu, 25 Aug 2016 15:09:03 +0200
Subject: [PATCH] Ticket #3666: Improper use of IEC and SI prefixes for size in
size_trunc_len()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
size_trunc_len() has been aligned to properly use either IEC or SI prefixes with
the unit B (byte). Additionally always put a space between number and unit which
is required by the norms.
It is important to note that really small buffers have to be bigger than it
appears because they store bytes and non-Latin scripts need more than one byte
with UTF-8 to encode them, e.g., the string "1023 МиБ" in Russian requires
11 bytes + null terminator.
---
lib/util.c | 33 ++++++++++++++++++++-------------
src/filemanager/filegui.c | 4 ++--
src/filemanager/info.c | 12 +++++++-----
src/filemanager/panel.c | 9 +++++----
4 files changed, 34 insertions(+), 24 deletions(-)
diff --git a/lib/util.c b/lib/util.c
index 304351d..3d497cf 100644
a
|
b
|
size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gbool |
449 | 449 | #endif |
450 | 450 | }; |
451 | 451 | /* *INDENT-ON* */ |
452 | | static const char *const suffix[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL }; |
453 | | static const char *const suffix_lc[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL }; |
| 452 | static const char *const units_iec[] = { N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), |
| 453 | N_("PiB"), NULL }; |
| 454 | static const char *const units_si[] = { N_("B"), N_("kB"), N_("MB"), N_("GB"), N_("TB"), |
| 455 | N_("PB"), NULL }; |
454 | 456 | |
455 | | const char *const *sfx = use_si ? suffix_lc : suffix; |
| 457 | const char *const *sfx = use_si ? units_si : units_iec; |
456 | 458 | int j = 0; |
457 | 459 | |
458 | 460 | if (len == 0) |
459 | 461 | len = 9; |
460 | 462 | #if SIZEOF_UINTMAX_T == 8 |
461 | 463 | /* 20 decimal digits are required to represent 8 bytes */ |
462 | | else if (len > 19) |
463 | | len = 19; |
| 464 | else if (len > 21) |
| 465 | len = 21; |
464 | 466 | #else |
465 | 467 | /* 10 decimal digits are required to represent 4 bytes */ |
466 | | else if (len > 9) |
467 | | len = 9; |
| 468 | else if (len > 11) |
| 469 | len = 11; |
468 | 470 | #endif |
469 | 471 | |
470 | 472 | /* |
… |
… |
size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gbool |
489 | 491 | { |
490 | 492 | if (j == units) |
491 | 493 | { |
492 | | /* Empty files will print "0" even with minimal width. */ |
493 | | g_snprintf (buffer, len + 1, "%s", "0"); |
| 494 | /* Empty files will print "0 B" even with minimal width. */ |
| 495 | g_snprintf (buffer, len + 1, "0 %s", _("B")); |
494 | 496 | } |
495 | 497 | else |
496 | 498 | { |
497 | | /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */ |
498 | | g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", (j > 1) ? sfx[j - 1] : "B"); |
| 499 | /* Use "~KiB/kB" or just "KiB/kB" if len is 1. Use "B" for bytes. */ |
| 500 | g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", |
| 501 | (j > 1) ? _(sfx[j - 1]) : _("B")); |
499 | 502 | } |
500 | 503 | break; |
501 | 504 | } |
502 | 505 | |
503 | | if (size < power10[len - (j > 0 ? 1 : 0)]) |
| 506 | /* |
| 507 | * Offset calculation: 1 for space + 2*3 bytes for scaled units as multibyte |
| 508 | * encoding with UTF-8 for non-Latin scripts. |
| 509 | */ |
| 510 | if (size < power10[len - (1 + 6)]) |
504 | 511 | { |
505 | | g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, sfx[j]); |
| 512 | g_snprintf (buffer, len + 1, "%" PRIuMAX " %s", size, _(sfx[j])); |
506 | 513 | break; |
507 | 514 | } |
508 | 515 | |
diff --git a/src/filemanager/filegui.c b/src/filemanager/filegui.c
index 2b6871a..edf2502 100644
a
|
b
|
file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct |
1013 | 1013 | |
1014 | 1014 | if (ui->total_bytes_label != NULL) |
1015 | 1015 | { |
1016 | | size_trunc_len (buffer2, 5, tctx->copied_bytes, 0, panels_options.kilobyte_si); |
| 1016 | size_trunc_len (buffer2, 11, tctx->copied_bytes, 0, panels_options.kilobyte_si); |
1017 | 1017 | if (!ctx->progress_totals_computed) |
1018 | 1018 | g_snprintf (buffer, sizeof (buffer), _(" Total: %s "), buffer2); |
1019 | 1019 | else |
1020 | 1020 | { |
1021 | | size_trunc_len (buffer3, 5, ctx->progress_bytes, 0, panels_options.kilobyte_si); |
| 1021 | size_trunc_len (buffer3, 11, ctx->progress_bytes, 0, panels_options.kilobyte_si); |
1022 | 1022 | g_snprintf (buffer, sizeof (buffer), _(" Total: %s/%s "), buffer2, buffer3); |
1023 | 1023 | } |
1024 | 1024 | |
diff --git a/src/filemanager/info.c b/src/filemanager/info.c
index cb5cf6a..888d6fc 100644
a
|
b
|
info_show_info (WInfo * info) |
176 | 176 | tty_print_string (_("No space information")); |
177 | 177 | else |
178 | 178 | { |
179 | | char buffer1[6], buffer2[6]; |
| 179 | char buffer1[12], buffer2[12]; |
180 | 180 | |
181 | | size_trunc_len (buffer1, 5, myfs_stats.avail, 1, panels_options.kilobyte_si); |
182 | | size_trunc_len (buffer2, 5, myfs_stats.total, 1, panels_options.kilobyte_si); |
| 181 | size_trunc_len (buffer1, sizeof(buffer1) - 1, myfs_stats.avail, 1, |
| 182 | panels_options.kilobyte_si); |
| 183 | size_trunc_len (buffer2, sizeof(buffer2) - 1, myfs_stats.total, 1, |
| 184 | panels_options.kilobyte_si); |
183 | 185 | tty_printf (_("Free space: %s/%s (%d%%)"), buffer1, buffer2, |
184 | 186 | myfs_stats.total == 0 ? 0 : |
185 | 187 | (int) (100 * (long double) myfs_stats.avail / myfs_stats.total)); |
… |
… |
info_show_info (WInfo * info) |
232 | 234 | else |
233 | 235 | #endif |
234 | 236 | { |
235 | | char buffer[10]; |
236 | | size_trunc_len (buffer, 9, st.st_size, 0, panels_options.kilobyte_si); |
| 237 | char buffer[12]; |
| 238 | size_trunc_len (buffer, sizeof(buffer) - 1, st.st_size, 0, panels_options.kilobyte_si); |
237 | 239 | tty_printf (_("Size: %s"), buffer); |
238 | 240 | #ifdef HAVE_STRUCT_STAT_ST_BLOCKS |
239 | 241 | tty_printf (ngettext (" (%ld block)", " (%ld blocks)", |
diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c
index b18cbac..cbaac3e 100644
a
|
b
|
static panel_field_t panel_fields[] = { |
195 | 195 | } |
196 | 196 | , |
197 | 197 | { |
198 | | "size", 7, FALSE, J_RIGHT, |
| 198 | "size", 8, FALSE, J_RIGHT, |
199 | 199 | /* TRANSLATORS: one single character to represent 'size' sort mode */ |
200 | 200 | /* TRANSLATORS: no need to translate 'sort', it's just a context prefix */ |
201 | 201 | N_("sort|s"), |
… |
… |
static panel_field_t panel_fields[] = { |
205 | 205 | } |
206 | 206 | , |
207 | 207 | { |
208 | | "bsize", 7, FALSE, J_RIGHT, |
| 208 | "bsize", 8, FALSE, J_RIGHT, |
209 | 209 | "", |
210 | 210 | N_("Block Size"), FALSE, FALSE, |
211 | 211 | string_file_size_brief, |
… |
… |
string_file_size (file_entry_t * fe, int len) |
515 | 515 | format_device_number (buffer, len + 1, fe->st.st_rdev); |
516 | 516 | else |
517 | 517 | #endif |
518 | | size_trunc_len (buffer, (unsigned int) len, fe->st.st_size, 0, panels_options.kilobyte_si); |
| 518 | size_trunc_len (buffer, (unsigned int) (len + 3), fe->st.st_size, 0, |
| 519 | panels_options.kilobyte_si); |
519 | 520 | |
520 | 521 | return buffer; |
521 | 522 | } |
… |
… |
show_free_space (const WPanel * panel) |
1154 | 1155 | if (myfs_stats.avail != 0 || myfs_stats.total != 0) |
1155 | 1156 | { |
1156 | 1157 | const Widget *w = CONST_WIDGET (panel); |
1157 | | char buffer1[6], buffer2[6], tmp[BUF_SMALL]; |
| 1158 | char buffer1[12], buffer2[12], tmp[BUF_SMALL]; |
1158 | 1159 | |
1159 | 1160 | size_trunc_len (buffer1, sizeof (buffer1) - 1, myfs_stats.avail, 1, |
1160 | 1161 | panels_options.kilobyte_si); |