1 /*******************************************************************************
2  * tlx/string/parse_si_iec_units.cpp
3  *
4  * Part of tlx - http://panthema.net/tlx
5  *
6  * Copyright (C) 2016-2017 Timo Bingmann <tb@panthema.net>
7  *
8  * All rights reserved. Published under the Boost Software License, Version 1.0
9  ******************************************************************************/
10 
11 #include <tlx/string/parse_si_iec_units.hpp>
12 
13 #include <cstdlib>
14 
15 namespace tlx {
16 
parse_si_iec_units(const char * str,uint64_t * out_size,char default_unit)17 bool parse_si_iec_units(
18     const char* str, uint64_t* out_size, char default_unit) {
19 
20     char* endptr;
21     *out_size = strtoul(str, &endptr, 10);
22     if (endptr == nullptr) return false;        // parse failed, no number
23 
24     while (*endptr == ' ') ++endptr;            // skip over spaces
25 
26     // multiply with base ^ power
27     unsigned int base = 1000;
28     unsigned int power = 0;
29 
30     if (*endptr == 'k' || *endptr == 'K')
31         power = 1, ++endptr;
32     else if (*endptr == 'm' || *endptr == 'M')
33         power = 2, ++endptr;
34     else if (*endptr == 'g' || *endptr == 'G')
35         power = 3, ++endptr;
36     else if (*endptr == 't' || *endptr == 'T')
37         power = 4, ++endptr;
38     else if (*endptr == 'p' || *endptr == 'P')
39         power = 5, ++endptr;
40 
41     // switch to power of two (only if power was set above)
42     if ((*endptr == 'i' || *endptr == 'I') && power != 0)
43         base = 1024, ++endptr;
44 
45     // byte indicator
46     if (*endptr == 'b' || *endptr == 'B') {
47         ++endptr;
48     }
49     else if (power == 0)
50     {
51         // no explicit power indicator, and no 'b' or 'B' -> apply default unit
52         switch (default_unit)
53         {
54         default: break;
55         case 'k': power = 1, base = 1000;
56             break;
57         case 'm': power = 2, base = 1000;
58             break;
59         case 'g': power = 3, base = 1000;
60             break;
61         case 't': power = 4, base = 1000;
62             break;
63         case 'p': power = 5, base = 1000;
64             break;
65         case 'K': power = 1, base = 1024;
66             break;
67         case 'M': power = 2, base = 1024;
68             break;
69         case 'G': power = 3, base = 1024;
70             break;
71         case 'T': power = 4, base = 1024;
72             break;
73         case 'P': power = 5, base = 1024;
74             break;
75         }
76     }
77 
78     // skip over spaces
79     while (*endptr == ' ') ++endptr;
80 
81     // multiply size
82     for (unsigned int p = 0; p < power; ++p)
83         *out_size *= base;
84 
85     return (*endptr == 0);
86 }
87 
parse_si_iec_units(const std::string & str,uint64_t * out_size,char default_unit)88 bool parse_si_iec_units(
89     const std::string& str, uint64_t* out_size, char default_unit) {
90     return parse_si_iec_units(str.c_str(), out_size, default_unit);
91 }
92 
93 } // namespace tlx
94 
95 /******************************************************************************/
96