270 lines
5.8 KiB
C
270 lines
5.8 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License v2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 021110-1307, USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "common/units.h"
|
|
#include "common/messages.h"
|
|
|
|
/*
|
|
* Note: this function uses a static per-thread buffer. Do not call this
|
|
* function more than 10 times within one argument list!
|
|
*/
|
|
const char *pretty_size_mode(u64 size, unsigned mode)
|
|
{
|
|
static __thread int ps_index = 0;
|
|
static __thread char ps_array[10][32];
|
|
char *ret;
|
|
|
|
ret = ps_array[ps_index];
|
|
ps_index++;
|
|
ps_index %= 10;
|
|
(void)pretty_size_snprintf(size, ret, 32, mode);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const char* unit_suffix_binary[] =
|
|
{ "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
|
|
static const char* unit_suffix_decimal[] =
|
|
{ "B", "kB", "MB", "GB", "TB", "PB", "EB"};
|
|
|
|
int pretty_size_snprintf(u64 size, char *str, size_t str_size, unsigned unit_mode)
|
|
{
|
|
int num_divs;
|
|
float fraction;
|
|
u64 base = 0;
|
|
int mult = 0;
|
|
const char** suffix = NULL;
|
|
u64 last_size;
|
|
int negative;
|
|
|
|
if (str_size == 0)
|
|
return 0;
|
|
|
|
negative = !!(unit_mode & UNITS_NEGATIVE);
|
|
unit_mode &= ~UNITS_NEGATIVE;
|
|
|
|
if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_RAW) {
|
|
if (negative)
|
|
snprintf(str, str_size, "%lld", size);
|
|
else
|
|
snprintf(str, str_size, "%llu", size);
|
|
return 0;
|
|
}
|
|
|
|
if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_BINARY) {
|
|
base = 1024;
|
|
mult = 1024;
|
|
suffix = unit_suffix_binary;
|
|
} else if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_DECIMAL) {
|
|
base = 1000;
|
|
mult = 1000;
|
|
suffix = unit_suffix_decimal;
|
|
}
|
|
|
|
/* Unknown mode */
|
|
if (!base) {
|
|
internal_error("unknown unit base, mode %u", unit_mode);
|
|
UASSERT(0);
|
|
return -1;
|
|
}
|
|
|
|
num_divs = 0;
|
|
last_size = size;
|
|
switch (unit_mode & UNITS_MODE_MASK) {
|
|
case UNITS_TBYTES:
|
|
base *= mult;
|
|
num_divs++;
|
|
fallthrough;
|
|
case UNITS_GBYTES:
|
|
base *= mult;
|
|
num_divs++;
|
|
fallthrough;
|
|
case UNITS_MBYTES:
|
|
base *= mult;
|
|
num_divs++;
|
|
fallthrough;
|
|
case UNITS_KBYTES:
|
|
num_divs++;
|
|
break;
|
|
case UNITS_BYTES:
|
|
base = 1;
|
|
num_divs = 0;
|
|
break;
|
|
default:
|
|
if (negative) {
|
|
s64 ssize = (s64)size;
|
|
s64 last_ssize = ssize;
|
|
|
|
while ((ssize < 0 ? -ssize : ssize) >= mult) {
|
|
last_ssize = ssize;
|
|
ssize /= mult;
|
|
num_divs++;
|
|
}
|
|
last_size = (u64)last_ssize;
|
|
} else {
|
|
while (size >= mult) {
|
|
last_size = size;
|
|
size /= mult;
|
|
num_divs++;
|
|
}
|
|
}
|
|
/*
|
|
* If the value is smaller than base, we didn't do any
|
|
* division, in that case, base should be 1, not original
|
|
* base, or the unit will be wrong
|
|
*/
|
|
if (num_divs == 0)
|
|
base = 1;
|
|
}
|
|
|
|
if (num_divs >= ARRAY_SIZE(unit_suffix_binary)) {
|
|
str[0] = '\0';
|
|
internal_error("unsupported unit suffix, index %d", num_divs);
|
|
UASSERT(0);
|
|
return -1;
|
|
}
|
|
|
|
if (negative) {
|
|
fraction = (float)(s64)last_size / base;
|
|
} else {
|
|
fraction = (float)last_size / base;
|
|
}
|
|
|
|
return snprintf(str, str_size, "%.2f%s", fraction, suffix[num_divs]);
|
|
}
|
|
|
|
void units_set_mode(unsigned *units, unsigned mode)
|
|
{
|
|
unsigned base = *units & UNITS_MODE_MASK;
|
|
|
|
*units = base | mode;
|
|
}
|
|
|
|
void units_set_base(unsigned *units, unsigned base)
|
|
{
|
|
unsigned mode = *units & ~UNITS_MODE_MASK;
|
|
|
|
*units = base | mode;
|
|
}
|
|
|
|
unsigned int get_unit_mode_from_arg(int *argc, char *argv[], int df_mode)
|
|
{
|
|
unsigned int unit_mode = UNITS_DEFAULT;
|
|
int arg_i;
|
|
int arg_end;
|
|
|
|
for (arg_i = 0; arg_i < *argc; arg_i++) {
|
|
if (!strcmp(argv[arg_i], "--"))
|
|
break;
|
|
|
|
if (!strcmp(argv[arg_i], "--raw")) {
|
|
unit_mode = UNITS_RAW;
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "--human-readable")) {
|
|
unit_mode = UNITS_HUMAN_BINARY;
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (!strcmp(argv[arg_i], "--iec")) {
|
|
units_set_mode(&unit_mode, UNITS_BINARY);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "--si")) {
|
|
units_set_mode(&unit_mode, UNITS_DECIMAL);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (!strcmp(argv[arg_i], "--kbytes")) {
|
|
units_set_base(&unit_mode, UNITS_KBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "--mbytes")) {
|
|
units_set_base(&unit_mode, UNITS_MBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "--gbytes")) {
|
|
units_set_base(&unit_mode, UNITS_GBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "--tbytes")) {
|
|
units_set_base(&unit_mode, UNITS_TBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (!df_mode)
|
|
continue;
|
|
|
|
if (!strcmp(argv[arg_i], "-b")) {
|
|
unit_mode = UNITS_RAW;
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-h")) {
|
|
unit_mode = UNITS_HUMAN_BINARY;
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-H")) {
|
|
unit_mode = UNITS_HUMAN_DECIMAL;
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-k")) {
|
|
units_set_base(&unit_mode, UNITS_KBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-m")) {
|
|
units_set_base(&unit_mode, UNITS_MBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-g")) {
|
|
units_set_base(&unit_mode, UNITS_GBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
if (!strcmp(argv[arg_i], "-t")) {
|
|
units_set_base(&unit_mode, UNITS_TBYTES);
|
|
argv[arg_i] = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
for (arg_i = 0, arg_end = 0; arg_i < *argc; arg_i++) {
|
|
if (!argv[arg_i])
|
|
continue;
|
|
argv[arg_end] = argv[arg_i];
|
|
arg_end++;
|
|
}
|
|
|
|
*argc = arg_end;
|
|
|
|
return unit_mode;
|
|
}
|
|
|