diff mbox series

[XTF,3/4] libc, strtol: Add FreeBSD libc implementation of strtoul()

Message ID 20200423101918.13566-4-wipawel@amazon.de (mailing list archive)
State New, archived
Headers show
Series Add strncmp(), strtol() and strtoul() functions | expand

Commit Message

Wieczorkiewicz, Pawel April 23, 2020, 10:19 a.m. UTC
The function was derived from:
https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/strtoul.c

Sligthly modified to use ctypes helpers and ignore locale.

Signed-off-by: Pawel Wieczorkiewicz <wipawel@amazon.de>
---
 common/libc/strtol.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/xtf/libc.h   |  1 +
 2 files changed, 70 insertions(+)
diff mbox series

Patch

diff --git a/common/libc/strtol.c b/common/libc/strtol.c
index f85ac7a..66ba787 100644
--- a/common/libc/strtol.c
+++ b/common/libc/strtol.c
@@ -130,3 +130,72 @@  long strtol(const char *nptr, char **endptr, int base)
         *endptr = (char *)(any ? s - 1 : nptr);
     return (acc);
 }
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+    const char *s = nptr;
+    unsigned long acc;
+    unsigned char c;
+    unsigned long cutoff;
+    int neg = 0, any, cutlim;
+
+    /*
+     * See strtol for comments as to the logic used.
+     */
+    do {
+        c = *s++;
+    } while (isspace(c));
+    if (c == '-') {
+        neg = 1;
+        c = *s++;
+    } else if (c == '+')
+        c = *s++;
+    if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
+        c = s[1];
+        s += 2;
+        base = 16;
+    }
+    if (base == 0)
+        base = c == '0' ? 8 : 10;
+    acc = any = 0;
+    if (base < 2 || base > 36)
+        goto noconv;
+
+    cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+    cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+    for ( ; ; c = *s++) {
+        if (isdigit(c))
+            c -= '0';
+        else if (c >= 'A' && c <= 'Z')
+            c -= 'A' - 10;
+        else if (c >= 'a' && c <= 'z')
+            c -= 'a' - 10;
+        else
+            break;
+        if (c >= base)
+            break;
+        if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+            any = -1;
+        else {
+            any = 1;
+            acc *= base;
+            acc += c;
+        }
+    }
+    if (any < 0) {
+        acc = ULONG_MAX;
+    } else if (!any) {
+noconv: ;
+    } else if (neg)
+        acc = -acc;
+    if (endptr != NULL)
+        *endptr = (char *)(any ? s - 1 : nptr);
+    return (acc);
+}
diff --git a/include/xtf/libc.h b/include/xtf/libc.h
index 0caa7d3..75f193b 100644
--- a/include/xtf/libc.h
+++ b/include/xtf/libc.h
@@ -36,6 +36,7 @@  int memcmp(const void *s1, const void *s2, size_t n);
 #define memcmp(s1, s2, n)           __builtin_memcmp(s1, s2, n)
 
 long strtol(const char *nptr, char **endptr, int base);
+unsigned long strtoul(const char *nptr, char **endptr, int base);
 
 size_t strnlen(const char *str, size_t max);