#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SECTOR_SIZE_DEFAULT 512LL
#define KILOBYTE_SIZE 1000LL
#define MEGABYTE_SIZE 1000000LL
#define GIGABYTE_SIZE 1000000000LL
#define TERABYTE_SIZE 1000000000000LL
#define KIBIBYTE_SIZE 1024LL
#define MEBIBYTE_SIZE 1048576LL
#define GIBIBYTE_SIZE 1073741824LL
#define TEBIBYTE_SIZE 1099511627776LL
typedef enum
{
BASE_BINARY,
BASE_DECIMAL
} Base;
typedef enum {
DIGIT_UNIT_BYTE,
DIGIT_UNIT_KILOBYTE,
DIGIT_UNIT_MEGABYTE,
DIGIT_UNIT_GIGABYTE,
DIGIT_UNIT_TERABYTE,
DIGIT_UNIT_KIBIBYTE,
DIGIT_UNIT_MEBIBYTE,
DIGIT_UNIT_GIBIBYTE,
DIGIT_UNIT_TEBIBYTE
} DigitUnit;
char *
unit_format_custom (long long n, DigitUnit unit)
{
char *str = malloc(64);
memset (str, 0, 64);
float f;
int len;
char *suffix;
switch (unit)
{
case DIGIT_UNIT_BYTE:
{
sprintf (str, "%lld%s", n, "B");
break;
}
case DIGIT_UNIT_KILOBYTE:
{
f = (float) n / KILOBYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "K");
break;
}
case DIGIT_UNIT_MEGABYTE:
{
f = (float) n / MEGABYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "M");
break;
}
case DIGIT_UNIT_GIGABYTE:
{
f = (float) n / GIGABYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "G");
break;
}
case DIGIT_UNIT_TERABYTE:
{
f = (float) n / TERABYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "T");
break;
}
case DIGIT_UNIT_KIBIBYTE:
{
f = (float) n / KIBIBYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "Ki");
break;
}
case DIGIT_UNIT_MEBIBYTE:
{
f = (float) n / MEBIBYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "Mi");
break;
}
case DIGIT_UNIT_GIBIBYTE:
{
f = (float) n / GIBIBYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "Gi");
break;
}
case DIGIT_UNIT_TEBIBYTE:
{
f = (float) n / TEBIBYTE_SIZE;
sprintf (str, "%.1f", f);
len = strlen(str);
suffix = (*(str + (len - 1)) == '0') ? str + len - 2 : str + len;
memset (suffix, 0, 2);
sprintf (suffix, "%s", "Ti");
break;
}
}
return str;
}
char *
unit_format (long long n, Base base)
{
DigitUnit unit = DIGIT_UNIT_BYTE - 1;
long long tmp = n;
if (base == BASE_DECIMAL)
{
while (tmp > 0)
{
tmp /= 1000;
unit++;
}
}
else if (base == BASE_BINARY)
{
while (tmp > 0)
{
tmp /= 1024;
unit++;
if (unit == DIGIT_UNIT_KILOBYTE)
{
unit = DIGIT_UNIT_KIBIBYTE;
}
}
}
return unit_format_custom (n, unit);
}
int main(int argc, char **argv)
{
printf ("%s\n", unit_format_custom (25678, DIGIT_UNIT_KILOBYTE));
printf ("%s\n", unit_format (4096, BASE_BINARY));
printf ("%s\n", unit_format (4096, BASE_DECIMAL));
printf ("%s\n", unit_format (8192, BASE_BINARY));
printf ("%s\n", unit_format (8192, BASE_DECIMAL));
return 0;
}