cosmopolitan/libc/fmt/sizetol.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

108 lines
3.9 KiB
C
Raw Normal View History

2020-06-15 14:18:57 +00:00
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
2020-06-15 14:18:57 +00:00
2020-12-28 01:18:44 +00:00
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
2020-06-15 14:18:57 +00:00
2020-12-28 01:18:44 +00:00
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
2020-06-15 14:18:57 +00:00
*/
2024-07-21 22:54:17 +00:00
#include "libc/ctype.h"
#include "libc/fmt/conv.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
2020-06-15 14:18:57 +00:00
static int GetExponent(int c) {
switch (c) {
case '\0':
case ' ':
case '\t':
return 0;
case 'k':
case 'K':
return 1;
case 'm':
case 'M':
return 2;
case 'g':
case 'G':
return 3;
case 't':
case 'T':
return 4;
case 'p':
case 'P':
return 5;
case 'e':
case 'E':
return 6;
default:
return -1;
}
2020-06-15 14:18:57 +00:00
}
/**
* Converts size string to long.
*
* The following unit suffixes may be used
*
* - `k` or `K` for kilo (multiply by 𝑏¹)
* - `m` or `M` for mega (multiply by 𝑏²)
* - `g` or `G` for giga (multiply by 𝑏³)
* - `t` or `T` for tera (multiply by 𝑏)
* - `p` or `P` for peta (multiply by 𝑏)
* - `e` or `E` for exa (multiply by 𝑏)
*
* If a permitted alpha character is supplied, then any additional
* characters after it (e.g. kbit, Mibit, TiB) are ignored. Spaces
* before the integer are ignored, and overflows will be detected.
*
* Negative numbers are permissible, as well as a leading `+` sign. To
* tell the difference between an error return and `-1` you must clear
* `errno` before calling and test whether it changed.
*
* @param s is non-null nul-terminated input string
* @param b is multiplier which should be 1000 or 1024
* @return size greater than or equal 0 or -1 on error
* @error EINVAL if error is due to bad syntax
* @error EOVERFLOW if error is due to overflow
*/
long sizetol(const char *s, long b) {
long x;
int c, e, d;
do {
c = *s++;
} while (c == ' ' || c == '\t');
d = c == '-' ? -1 : 1;
if (c == '-' || c == '+')
c = *s++;
if (!isdigit(c)) {
return einval();
}
x = 0;
do {
if (ckd_mul(&x, x, 10) || ckd_add(&x, x, (c - '0') * d)) {
return eoverflow();
}
} while (isdigit((c = *s++)));
if ((e = GetExponent(c)) == -1) {
return einval();
}
while (e--) {
if (ckd_mul(&x, x, b)) {
return eoverflow();
}
}
return x;
}