From 22619d0a64bd1792d721346650e928d7de578d35 Mon Sep 17 00:00:00 2001
From: Armin Luntzer <armin.luntzer@univie.ac.at>
Date: Wed, 6 Jun 2018 13:43:19 +0200
Subject: [PATCH] add string functions: isalpha(), isupper(), islower(), 
 strtol()

---
 include/kernel/string.h |   5 ++
 lib/string.c            | 172 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/include/kernel/string.h b/include/kernel/string.h
index 9b4859c..b5a18ad 100644
--- a/include/kernel/string.h
+++ b/include/kernel/string.h
@@ -31,7 +31,12 @@ void bzero(void *s, size_t n);
 
 int isdigit(int c);
 int isspace(int c);
+int isalpha(int c);
+int isupper(int c);
+int islower(int c);
+
 int atoi(const char *nptr);
+long int strtol(const char *nptr, char **endptr, int base);
 
 
 int vprintf(const char *format, va_list ap);
diff --git a/lib/string.c b/lib/string.c
index 9ab889e..2711901 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -18,6 +18,8 @@
 #include <kernel/types.h>
 #include <kernel/string.h>
 #include <kernel/printk.h>
+#include <kernel/log2.h>
+#include <kernel/bitops.h>
 
 
 /**
@@ -486,6 +488,57 @@ int isdigit(int c)
 }
 EXPORT_SYMBOL(isdigit);
 
+
+/**
+ * @brief check if a character is from the alphabet
+ *
+ * @param c the character to test
+ *
+ * @returns 0 if not in the alphabet
+ *
+ * @note in ASCII, 'a-z' are 'A-Z' + 32
+ */
+
+int isalpha(int c)
+{
+	return ((unsigned char) c | 0x20) - 'a' < 26;
+}
+EXPORT_SYMBOL(isalpha);
+
+
+/**
+ * @brief check if an alphabetic character is in uppercase
+ *
+ * @param c the character to test
+ *
+ * @returns 0 if lowercase or out of range
+ *
+ */
+
+int isupper(int c)
+{
+    return c >= 'A' && c <= 'Z';
+}
+EXPORT_SYMBOL(isupper);
+
+
+/**
+ * @brief check if an alphabetic character is in lowercase
+ *
+ * @param c the character to test
+ *
+ * @returns 0 if uppercase or out of range
+ *
+ */
+
+int islower(int c)
+{
+    return c >= 'a' && c <= 'z';
+}
+EXPORT_SYMBOL(islower);
+
+
+
 /**
  * @brief convert a string to an integer
  *
@@ -549,3 +602,122 @@ void *memset(void *s, int c, size_t n)
 	return s;
 }
 EXPORT_SYMBOL(memset);
+
+
+
+/**
+ * @brief convert a string to a long integer
+ *
+ * @param nptr	the pointer to a string (possibly) representing a number
+ * @param endptr if not NULL, stores the pointer to the first character not part
+ *		 of the number
+ * @param base  the base of the number string
+ *
+ * @return the converted number
+ *
+ * @note A base of 0 defaults to 10 unless the first character after
+ *	 ' ', '+' or '-' is a '0', which will default it to base 8, unless
+ *	 it is followed by 'x' or 'X'  which defaults to base 16.
+ *	 If a number is not preceeded by a sign, it is assumed to be a unsigned
+ *	 type and may therefore assume the size of ULONG_MAX.
+ *	 If no number has been found, the function will return 0 and
+ *	 nptr == endptr
+ *
+ * @note if the value would over-/underflow, LONG_MAX/MIN is returned
+ */
+
+long int strtol(const char *nptr, char **endptr, int base)
+{
+	int neg = 0;
+
+	unsigned long res = 0;
+	unsigned long clamp = (unsigned long) ULONG_MAX;
+
+
+
+	if (endptr)
+		(*endptr) = (char *) nptr;
+
+	for (; isspace(*nptr); nptr++);
+
+
+	if ((*nptr) == '-') {
+		nptr++;
+		neg = 1;
+		clamp = -(unsigned long) LONG_MIN;
+	} else if ((*nptr) == '+') {
+		clamp =  (unsigned long) LONG_MAX;
+		nptr++;
+	}
+
+	if (!base || base == 16) {
+		if ((*nptr) == '0') {
+			switch (nptr[1]) {
+			case 'x':
+			case 'X':
+				nptr += 2;
+				base = 16;
+				break;
+			default:
+				nptr++;
+				base = 8;
+				break;
+			}
+		} else {
+			/* default */
+			base = 10;
+		}
+	}
+
+
+	/* Now iterate over the string and add up the digits. We convert
+	 * any A-Z to a-z (offset == 32 in ASCII) to check if the string
+	 * contains letters representing values (A=10...Z=35). We abort if
+	 * the computed digit value exceeds the given base or on overflow.
+	 */
+
+	while (1) {
+		unsigned int c = (*nptr);
+		unsigned int l = c | 0x20;
+		unsigned int val;
+
+		if (isdigit(c))
+			val = c - '0';
+		else if (islower(l))
+		       val = l - 'a' + 10;
+		else
+			break;
+
+		if (val >= base)
+			break;
+
+		/* Check for overflow only if result is approximately within
+		 * range of it, given the base. If we overflow, set result
+		 * to clamp (LONG_MAX or LONG_MIN)
+		 */
+
+		if (res & (~0UL << (BITS_PER_LONG - fls(base)))) {
+	               if (res > (clamp - val) / base) {
+			       res = clamp;
+			       break;
+		       }
+		}
+
+		res = res * base + val;
+		nptr++;
+	}
+
+
+	/* update endptr if a value was found */
+	if (res)
+		if (endptr)
+			(*endptr) = (char *) nptr;
+
+
+	if (neg)
+		return - (long int) res;
+
+	return (long int) res;
+}
+
+
-- 
GitLab