master xplshn/aruu / shared / libutil / parseoffset.c
 1/* See LICENSE file for copyright and license details. */
 2#include <ctype.h>
 3#include <errno.h>
 4#include <inttypes.h>
 5#include <stdlib.h>
 6#include <string.h>
 7
 8#include "../util.h"
 9
10off_t
11parseoffset(const char *str)
12{
13  off_t res, scale = 1;
14  char *end;
15
16  /* strictly check what strtol() usually would let pass */
17  if (!str || !*str || isspace(*str) || *str == '+' || *str == '-') {
18    weprintf("parseoffset %s: invalid value\n", str);
19    return -1;
20  }
21
22  errno = 0;
23  res   = strtol(str, &end, 0);
24  if (errno) {
25    weprintf("parseoffset %s: invalid value\n", str);
26    return -1;
27  }
28  if (res < 0) {
29    weprintf("parseoffset %s: negative value\n", str);
30    return -1;
31  }
32
33  /* suffix */
34  if (*end) {
35    switch (toupper((int)*end)) {
36      case 'B':
37        scale = 512L;
38        break;
39      case 'K':
40        scale = 1024L;
41        break;
42      case 'M':
43        scale = 1024L * 1024L;
44        break;
45      case 'G':
46        scale = 1024L * 1024L * 1024L;
47        break;
48      default:
49        weprintf("parseoffset %s: invalid suffix '%s'\n", str, end);
50        return -1;
51    }
52  }
53
54  /* prevent overflow */
55  if (res > (SSIZE_MAX / scale)) {
56    weprintf("parseoffset %s: out of range\n", str);
57    return -1;
58  }
59
60  return res * scale;
61}