1 #include <stdio.h>
2
3 #define SECTOR_SIZE_DEFAULT 512LL
4 #define KILOBYTE_SIZE 1000LL
5 #define MEGABYTE_SIZE 1000000LL
6 #define GIGABYTE_SIZE 1000000000LL
7 #define TERABYTE_SIZE 1000000000000LL
8 #define KIBIBYTE_SIZE 1024LL
9 #define MEBIBYTE_SIZE 1048576LL
10 #define GIBIBYTE_SIZE 1073741824LL
11 #define TEBIBYTE_SIZE 1099511627776LL
12
13 typedef enum {
14 DIGIT_UNIT_BYTE,
15 DIGIT_UNIT_KILOBYTE,
16 DIGIT_UNIT_MEGABYTE,
17 DIGIT_UNIT_GIGABYTE,
18 DIGIT_UNIT_TERABYTE,
19 DIGIT_UNIT_KIBIBYTE,
20 DIGIT_UNIT_MEBIBYTE,
21 DIGIT_UNIT_GIBIBYTE,
22 DIGIT_UNIT_TEBIBYTE
23 } DigitUnit;
24
25 /* Inefficiently removes all spaces from a string, in-place. */
26 static void
27 strip_string (char* str)
28 {
29 int i;
30
31 for (i = 0; str[i] != 0; i++) {
32 if (isspace (str[i])) {
33 int j;
34 for (j = i + 1; str[j] != 0; j++)
35 str[j - 1] = str[j];
36 }
37 }
38 }
39
40 /* Find non-number suffix. Eg: find_suffix("32Mb") returns a pointer to
41 * "Mb". */
42 static char*
43 find_suffix (const char* str)
44 {
45 while (str[0] != 0 && (isdigit (str[0]) || strchr(",.-", str[0])))
46 str++;
47 return (char *) str;
48 }
49
50 static DigitUnit
51 parse_unit_suffix (const char* suffix)
52 {
53 if (strlen (suffix) > 1 && tolower (suffix[1]) == 'i') {
54 switch (tolower (suffix[0])) {
55 case 'k': return DIGIT_UNIT_KIBIBYTE;
56 case 'm': return DIGIT_UNIT_MEBIBYTE;
57 case 'g': return DIGIT_UNIT_GIBIBYTE;
58 case 't': return DIGIT_UNIT_TEBIBYTE;
59 }
60 } else if (strlen (suffix) > 0) {
61 switch (tolower (suffix[0])) {
62 case 'b': return DIGIT_UNIT_BYTE;
63 case 'k': return DIGIT_UNIT_KILOBYTE;
64 case 'm': return DIGIT_UNIT_MEGABYTE;
65 case 'g': return DIGIT_UNIT_GIGABYTE;
66 case 't': return DIGIT_UNIT_TERABYTE;
67 }
68 }
69
70 return -1;
71 }
72
73 long long unit_parse (const char *str)
74 {
75 char *suffix;
76 long long byte = -1;
77 long long byte_block = 1;
78
79 strip_string (str);
80 suffix = find_suffix (str);
81
82 DigitUnit unit = parse_unit_suffix (suffix);
83
84 switch (unit) {
85 case DIGIT_UNIT_BYTE:
86 break;
87 case DIGIT_UNIT_KILOBYTE:
88 byte_block = KILOBYTE_SIZE;
89 break;
90 case DIGIT_UNIT_MEGABYTE:
91 byte_block = MEGABYTE_SIZE;
92 break;
93 case DIGIT_UNIT_GIGABYTE:
94 byte_block = GIGABYTE_SIZE;
95 break;
96 case DIGIT_UNIT_TERABYTE:
97 byte_block = TERABYTE_SIZE;
98 break;
99 case DIGIT_UNIT_KIBIBYTE:
100 byte_block = KIBIBYTE_SIZE;
101 break;
102 case DIGIT_UNIT_MEBIBYTE:
103 byte_block = MEBIBYTE_SIZE;
104 break;
105 case DIGIT_UNIT_GIBIBYTE:
106 byte_block = GIBIBYTE_SIZE;
107 break;
108 case DIGIT_UNIT_TEBIBYTE:
109 byte_block = TEBIBYTE_SIZE;
110 break;
111 }
112
113 double temp = 0;
114 if (sscanf (str, "%lf", &temp) == 1)
115 byte = temp * byte_block;
116
117 return byte;
118 }
119
120
121 int main (int argc, char **argv)
122 {
123 if (argc > 1)
124 printf ("%lld\n", unit_parse (argv[1]));
125 return 0;
126 }