Revision 9f9b17a4 cutils.c

b/cutils.c
23 23
 */
24 24
#include "qemu-common.h"
25 25
#include "host-utils.h"
26
#include <math.h>
26 27

  
27 28
void pstrcpy(char *buf, int buf_size, const char *str)
28 29
{
......
283 284
}
284 285
#endif
285 286

  
287
/*
288
 * Convert string to bytes, allowing either B/b for bytes, K/k for KB,
289
 * M/m for MB, G/g for GB or T/t for TB. Default without any postfix
290
 * is MB. End pointer will be returned in *end, if not NULL. A valid
291
 * value must be terminated by whitespace, ',' or '\0'. Return -1 on
292
 * error.
293
 */
294
ssize_t strtosz(const char *nptr, char **end)
295
{
296
    ssize_t retval = -1;
297
    char *endptr, c;
298
    int mul_required = 0;
299
    double val, mul, integral, fraction;
300

  
301
    errno = 0;
302
    val = strtod(nptr, &endptr);
303
    if (isnan(val) || endptr == nptr || errno != 0) {
304
        goto fail;
305
    }
306
    integral = modf(val, &fraction);
307
    if (integral != 0) {
308
        mul_required = 1;
309
    }
310
    /*
311
     * Any whitespace character is fine for terminating the number,
312
     * in addition we accept ',' to handle strings where the size is
313
     * part of a multi token argument.
314
     */
315
    c = *endptr;
316
    if (isspace(c) || c == '\0' || c == ',') {
317
        c = 0;
318
    }
319
    switch (c) {
320
    case 'B':
321
    case 'b':
322
        mul = 1;
323
        if (mul_required) {
324
            goto fail;
325
        }
326
        break;
327
    case 'K':
328
    case 'k':
329
        mul = 1 << 10;
330
        break;
331
    case 0:
332
        if (mul_required) {
333
            goto fail;
334
        }
335
    case 'M':
336
    case 'm':
337
        mul = 1ULL << 20;
338
        break;
339
    case 'G':
340
    case 'g':
341
        mul = 1ULL << 30;
342
        break;
343
    case 'T':
344
    case 't':
345
        mul = 1ULL << 40;
346
        break;
347
    default:
348
        goto fail;
349
    }
350
    /*
351
     * If not terminated by whitespace, ',', or \0, increment endptr
352
     * to point to next character, then check that we are terminated
353
     * by an appropriate separating character, ie. whitespace, ',', or
354
     * \0. If not, we are seeing trailing garbage, thus fail.
355
     */
356
    if (c != 0) {
357
        endptr++;
358
        if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) {
359
            goto fail;
360
        }
361
    }
362
    if ((val * mul >= ~(size_t)0) || val < 0) {
363
        goto fail;
364
    }
365
    retval = val * mul;
366

  
367
fail:
368
    if (end) {
369
        *end = endptr;
370
    }
371

  
372
    return retval;
373
}

Also available in: Unified diff