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}