summaryrefslogtreecommitdiff
path: root/src/stdlib/wcstoumax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib/wcstoumax.c')
-rw-r--r--src/stdlib/wcstoumax.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c
new file mode 100644
index 00000000..a8f4680f
--- /dev/null
+++ b/src/stdlib/wcstoumax.c
@@ -0,0 +1,47 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+
+uintmax_t wcstoumax(const wchar_t *s, wchar_t **p, int base)
+{
+ /* Large enough for largest value in binary */
+ char buf[sizeof(uintmax_t)*8+2];
+ int sign = 0, skipped=0;
+
+ if (!p) p = (wchar_t **)&s;
+
+ if (base && (unsigned)base-2 > 36-2) {
+ *p = (wchar_t *)s;
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* Initial whitespace */
+ for (; iswspace(*s); s++);
+
+ /* Optional sign */
+ if (*s == '-') sign = *s++;
+ else if (*s == '+') s++;
+
+ /* Skip leading zeros but don't allow leading zeros before "0x". */
+ for (; s[0]=='0' && s[1]=='0'; s++) skipped=1;
+ if (skipped && (base==0 || base==16) && (s[1]|32)=='x') {
+ *p = (wchar_t *)(s+1);
+ return 0;
+ }
+
+ /* Convert to normal char string so we can use strtoumax */
+ buf[0] = sign;
+ if (wcstombs(buf+!!sign, s, sizeof buf-1) < 0) return 0;
+ buf[sizeof buf-1]=0;
+
+ /* Compute final position */
+ if (p) {
+ if ((base==0 || base==16) && s[0]=='0' && (s[1]|32)=='x' && iswxdigit(s[2])) s+=2;
+ for(;*s&&((unsigned)*s-'0'<base||((unsigned)*s|32)-'a'<base-10);s++);
+ *p = (wchar_t *)s;
+ }
+
+ return strtoumax(buf, 0, base);
+}