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 }