Add '--si', '-h'/'--human-readable' and '--block-size' global options,
which allow users to customize the way sizes are displayed.

Options and their format tries to mimic GNU ls utility.

Signed-off-by: Audrius Butkevicius <audrius.butkevic...@elastichosts.com>
---
 btrfs.c |    3 ++
 utils.c |  146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 utils.h |    6 +++
 3 files changed, 138 insertions(+), 17 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 691adef..6a8fc30 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -22,6 +22,8 @@
 #include "crc32c.h"
 #include "commands.h"
 #include "version.h"
+#include "ctree.h"
+#include "utils.h"
 
 static const char * const btrfs_cmd_group_usage[] = {
        "btrfs [--help] [--version] <group> [<group>...] <command> [<args>]",
@@ -291,6 +293,7 @@ int main(int argc, char **argv)
 
        crc32c_optimization_init();
 
+       handle_size_unit_args(&argc, &argv);
        fixup_argv0(argv, cmd->token);
        exit(cmd->fn(argc, argv));
 }
diff --git a/utils.c b/utils.c
index d660507..58c1919 100644
--- a/utils.c
+++ b/utils.c
@@ -16,6 +16,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#define _GNU_SOURCE
 #define _XOPEN_SOURCE 700
 #define __USE_XOPEN2K8
 #define __XOPEN2K8 /* due to an error in dirent.h, to get dirfd() */
@@ -1095,33 +1096,144 @@ out:
        return ret;
 }
 
-static char *size_strs[] = { "", "KB", "MB", "GB", "TB",
-                           "PB", "EB", "ZB", "YB"};
+static int sizes_format = SIZES_FORMAT_BYTES;
+static u64 sizes_divisor = 1;
+
+void remove_arg(int i, int *argc, char ***argv)
+{
+       while (i++ < *argc)
+               (*argv)[i - 1] = (*argv)[i];
+       (*argc)--;
+}
+
+void handle_size_unit_args(int *argc, char ***argv)
+{
+       int k;
+       int base = 1024;
+       char *suffix;
+       char *block_size;
+       u64 value;
+
+       for (k = *argc - 1; k >= 0; k--) {
+                if (!strcmp((*argv)[k], "-h") ||
+                    !strcmp((*argv)[k], "--human-readable")) {
+                       sizes_format = SIZES_FORMAT_HUMAN;
+                       remove_arg(k, argc, argv);
+                } else if (!strcmp((*argv)[k], "--si")) {
+                       sizes_format = SIZES_FORMAT_SI;
+                       remove_arg(k, argc, argv);
+                } else if (!strncmp((*argv)[k], "--block-size", 12)) {
+                       if (strlen((*argv)[k]) < 14 || (*argv)[k][12] != '=') {
+                               fprintf(stderr,
+                                        "--block-size requires an argument\n");
+                               exit(1);
+                       }
+
+                       sizes_format = SIZES_FORMAT_BLOCK;
+                       block_size = strchr((*argv)[k], '=');
+
+                       errno = 0;
+                       value = strtoull(++block_size, &suffix, 10);
+                       if (errno == ERANGE && value == ULLONG_MAX) {
+                               fprintf(stderr,
+                                        "--block-size argument '%s' too 
large\n",
+                                        block_size);
+                               exit(1);
+                       }
+                       if (suffix == block_size)
+                               value = 1;
+
+                       if (strlen(suffix) == 1 && value > 0) {
+                               base = 1024;
+                       } else if (strlen(suffix) == 2 && suffix[1] == 'B'
+                                   && value > 0) {
+                               base = 1000;
+                       /* Allow non-zero values without a suffix */
+                       } else if (strlen(suffix) != 0 || value == 0) {
+                               fprintf(stderr,
+                                        "invalid --block-size argument '%s'\n",
+                                        block_size);
+                               exit(1);
+                       }
+
+                       if (strlen(suffix) > 0) {
+                               switch(suffix[0]) {
+                                       case 'E':
+                                               sizes_divisor *= base;
+                                       case 'P':
+                                               sizes_divisor *= base;
+                                       case 'T':
+                                               sizes_divisor *= base;
+                                       case 'G':
+                                               sizes_divisor *= base;
+                                       case 'M':
+                                               sizes_divisor *= base;
+                                       case 'K':
+                                               sizes_divisor *= base;
+                                               break;
+                                       default:
+                                               fprintf(stderr,
+                                                        "invalid --block-size \
+argument '%s'\n",
+                                                        block_size);
+                                               exit(1);
+                               }
+                       }
+
+                       if (ULLONG_MAX / sizes_divisor < value) {
+                               fprintf(stderr,
+                                        "--block-size argument '%s' too 
large\n",
+                                        block_size);
+                               exit(1);
+                       }
+
+                       if (suffix != block_size)
+                               sizes_divisor *= value;
+
+                       remove_arg(k, argc, argv);
+               }
+       }
+}
+
+static char *size_strs[] = { "", "K", "M", "G", "T", "P", "E"};
 char *pretty_sizes(u64 size)
 {
        int num_divs = 0;
-        int pretty_len = 16;
+       int sizes_base = 1024;
        float fraction;
        char *pretty;
-
-       if( size < 1024 ){
-               fraction = size;
-               num_divs = 0;
+       char *sizes_suffix = "iB";
+       u64 last_size;
+
+       if (sizes_format == SIZES_FORMAT_BYTES) {
+               asprintf(&pretty, "%llu", (unsigned long long)size);
+       } else if (sizes_format == SIZES_FORMAT_BLOCK) {
+               fraction = (float)size / sizes_divisor;
+               asprintf(&pretty, "%.2f", fraction);
        } else {
-               u64 last_size = size;
-               num_divs = 0;
-               while(size >= 1024){
+               if (sizes_format == SIZES_FORMAT_SI) {
+                       sizes_base = 1000;
+                       sizes_suffix = "B";
+               }
+
+               if (size < sizes_base) {
+                       fraction = size;
+               } else {
                        last_size = size;
-                       size /= 1024;
-                       num_divs ++;
+                       while (size >= sizes_base) {
+                               last_size = size;
+                               size /= 1024;
+                               num_divs++;
+                       }
+
+                       if (num_divs > ARRAY_SIZE(size_strs))
+                               return NULL;
+                       fraction = (float)last_size / sizes_base;
                }
 
-               if (num_divs >= ARRAY_SIZE(size_strs))
-                       return NULL;
-               fraction = (float)last_size / 1024;
+               asprintf(&pretty, "%.2f%s%s", fraction, size_strs[num_divs],
+                         sizes_suffix);
        }
-       pretty = malloc(pretty_len);
-       snprintf(pretty, pretty_len, "%.2f%s", fraction, size_strs[num_divs]);
        return pretty;
 }
 
diff --git a/utils.h b/utils.h
index 60a0fea..56d7950 100644
--- a/utils.h
+++ b/utils.h
@@ -23,6 +23,11 @@
 
 #define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024)
 
+#define SIZES_FORMAT_BYTES 0
+#define SIZES_FORMAT_HUMAN 1
+#define SIZES_FORMAT_SI 2
+#define SIZES_FORMAT_BLOCK 3
+
 int make_btrfs(int fd, const char *device, const char *label,
               u64 blocks[6], u64 num_bytes, u32 nodesize,
               u32 leafsize, u32 sectorsize, u32 stripesize);
@@ -44,6 +49,7 @@ int check_mounted_where(int fd, const char *file, char 
*where, int size,
 int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
                                 int super_offset);
 char *pretty_sizes(u64 size);
+void handle_size_unit_args(int *argc, char ***argv);
 int check_label(char *input);
 int get_mountpt(char *dev, char *mntpt, size_t size);
 int btrfs_scan_block_devices(int run_ioctl);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to