@@ -128,3 +128,130 @@ int safe_atolli(const char *s, long long int *ret_lli) {
128128 * ret_lli = l ;
129129 return 0 ;
130130}
131+
132+ int parse_size (const char * t , uint64_t base , uint64_t * size ) {
133+
134+ /* Soo, sometimes we want to parse IEC binary suffixes, and
135+ * sometimes SI decimal suffixes. This function can parse
136+ * both. Which one is the right way depends on the
137+ * context. Wikipedia suggests that SI is customary for
138+ * hardware metrics and network speeds, while IEC is
139+ * customary for most data sizes used by software and volatile
140+ * (RAM) memory. Hence be careful which one you pick!
141+ *
142+ * In either case we use just K, M, G as suffix, and not Ki,
143+ * Mi, Gi or so (as IEC would suggest). That's because that's
144+ * frickin' ugly. But this means you really need to make sure
145+ * to document which base you are parsing when you use this
146+ * call. */
147+
148+ struct table {
149+ const char * suffix ;
150+ unsigned long long factor ;
151+ };
152+
153+ static const struct table iec [] = {
154+ { "E" , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL },
155+ { "P" , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL },
156+ { "T" , 1024ULL * 1024ULL * 1024ULL * 1024ULL },
157+ { "G" , 1024ULL * 1024ULL * 1024ULL },
158+ { "M" , 1024ULL * 1024ULL },
159+ { "K" , 1024ULL },
160+ { "B" , 1ULL },
161+ { "" , 1ULL },
162+ };
163+
164+ static const struct table si [] = {
165+ { "E" , 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL },
166+ { "P" , 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL },
167+ { "T" , 1000ULL * 1000ULL * 1000ULL * 1000ULL },
168+ { "G" , 1000ULL * 1000ULL * 1000ULL },
169+ { "M" , 1000ULL * 1000ULL },
170+ { "K" , 1000ULL },
171+ { "B" , 1ULL },
172+ { "" , 1ULL },
173+ };
174+
175+ const struct table * table ;
176+ const char * p ;
177+ unsigned long long r = 0 ;
178+ unsigned n_entries , start_pos = 0 ;
179+
180+ assert (t );
181+ assert (IN_SET (base , 1000 , 1024 ));
182+ assert (size );
183+
184+ if (base == 1000 ) {
185+ table = si ;
186+ n_entries = ELEMENTSOF (si );
187+ } else {
188+ table = iec ;
189+ n_entries = ELEMENTSOF (iec );
190+ }
191+
192+ p = t ;
193+ do {
194+ unsigned long long l , tmp ;
195+ double frac = 0 ;
196+ char * e ;
197+ unsigned i ;
198+
199+ p += strspn (p , WHITESPACE );
200+
201+ errno = 0 ;
202+ l = strtoull (p , & e , 10 );
203+ if (errno > 0 )
204+ return - errno ;
205+ if (e == p )
206+ return - EINVAL ;
207+ if (* p == '-' )
208+ return - ERANGE ;
209+
210+ if (* e == '.' ) {
211+ e ++ ;
212+
213+ /* strtoull() itself would accept space/+/- */
214+ if (ascii_isdigit (* e )) {
215+ unsigned long long l2 ;
216+ char * e2 ;
217+
218+ l2 = strtoull (e , & e2 , 10 );
219+ if (errno > 0 )
220+ return - errno ;
221+
222+ /* Ignore failure. E.g. 10.M is valid */
223+ frac = l2 ;
224+ for (; e < e2 ; e ++ )
225+ frac /= 10 ;
226+ }
227+ }
228+
229+ e += strspn (e , WHITESPACE );
230+
231+ for (i = start_pos ; i < n_entries ; i ++ )
232+ if (startswith (e , table [i ].suffix ))
233+ break ;
234+
235+ if (i >= n_entries )
236+ return - EINVAL ;
237+ if (l + (frac > 0 ) > ULLONG_MAX / table [i ].factor )
238+ return - ERANGE ;
239+
240+ tmp = l * table [i ].factor + (unsigned long long ) (frac * table [i ].factor );
241+ if (tmp > ULLONG_MAX - r )
242+ return - ERANGE ;
243+
244+ r += tmp ;
245+ if ((unsigned long long ) (uint64_t ) r != r )
246+ return - ERANGE ;
247+
248+ p = e + strlen (table [i ].suffix );
249+
250+ start_pos = i + 1 ;
251+
252+ } while (* p );
253+
254+ * size = r ;
255+
256+ return 0 ;
257+ }
0 commit comments