summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs/lib/strtoul.c
diff options
context:
space:
mode:
authorThorsten Lockert <tholo@cvs.openbsd.org>1996-04-27 19:43:32 +0000
committerThorsten Lockert <tholo@cvs.openbsd.org>1996-04-27 19:43:32 +0000
commit49126961fd129e607f88970e81ab6d48baaecda0 (patch)
tree8168bd6a7b92392e99d483a83c51b3f8f7df113d /gnu/usr.bin/cvs/lib/strtoul.c
parent61aa6f7b30e536382606a49e9a65374b125db338 (diff)
Latest public release from Cyclic; fixes numerous memory leaks and have
some performance improvements
Diffstat (limited to 'gnu/usr.bin/cvs/lib/strtoul.c')
-rw-r--r--gnu/usr.bin/cvs/lib/strtoul.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/gnu/usr.bin/cvs/lib/strtoul.c b/gnu/usr.bin/cvs/lib/strtoul.c
new file mode 100644
index 00000000000..7d42c210f67
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/strtoul.c
@@ -0,0 +1,100 @@
+/*
+ * strtol : convert a string to long.
+ *
+ * Andy Wilson, 2-Oct-89.
+ */
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef ULONG_MAX
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */
+#endif
+
+extern int errno;
+
+unsigned long
+strtoul(s, ptr, base)
+ const char *s; char **ptr; int base;
+{
+ unsigned long total = 0;
+ unsigned digit;
+ const char *start=s;
+ int did_conversion=0;
+ int overflow = 0;
+ int negate = 0;
+ unsigned long maxdiv, maxrem;
+
+ if (s==NULL)
+ {
+ errno = ERANGE;
+ if (!ptr)
+ *ptr = (char *)start;
+ return 0L;
+ }
+
+ while (isspace(*s))
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ s++, negate = 1;
+ if (base==0 || base==16) /* the 'base==16' is for handling 0x */
+ {
+ int tmp;
+
+ /*
+ * try to infer base from the string
+ */
+ if (*s != '0')
+ tmp = 10; /* doesn't start with 0 - assume decimal */
+ else if (s[1] == 'X' || s[1] == 'x')
+ tmp = 16, s += 2; /* starts with 0x or 0X - hence hex */
+ else
+ tmp = 8; /* starts with 0 - hence octal */
+ if (base==0)
+ base = (int)tmp;
+ }
+
+ maxdiv = ULONG_MAX / base;
+ maxrem = ULONG_MAX % base;
+
+ while ((digit = *s) != '\0')
+ {
+ if (digit >= '0' && digit < ('0'+base))
+ digit -= '0';
+ else
+ if (base > 10)
+ {
+ if (digit >= 'a' && digit < ('a'+(base-10)))
+ digit = digit - 'a' + 10;
+ else if (digit >= 'A' && digit < ('A'+(base-10)))
+ digit = digit - 'A' + 10;
+ else
+ break;
+ }
+ else
+ break;
+ did_conversion = 1;
+ if (total > maxdiv
+ || (total == maxdiv && digit > maxrem))
+ overflow = 1;
+ total = (total * base) + digit;
+ s++;
+ }
+ if (overflow)
+ {
+ errno = ERANGE;
+ if (ptr != NULL)
+ *ptr = (char *)s;
+ return (ULONG_MAX);
+ }
+ if (ptr != NULL)
+ *ptr = (char *) ((did_conversion) ? (char *)s : (char *)start);
+ return negate ? -total : total;
+}