libutil

C Utility Library
git clone http://git.omkov.net/libutil
Log | Tree | Refs | README | LICENCE | Download

AuthorJamozed <[email protected]>
Date2021-02-21 22:39:52
Commit9b704eb0a668dd41692320568dd951d4132613c6
Parent102f6ff42fbee51ffe6a6aa277967b6c519c0d60

strconv: Add signed string conversion functions

Diffstat

M CMakeLists.txt | 28 ++++++++++++++--------------
M README.md | 2 ++
M src/strconv.h | 8 +++++++-
A src/strtoi.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/strtou.c | 2 +-
R src/test/test_strconv.c -> src/test/test_strtou.c | 1 +

6 files changed, 189 insertions, 16 deletions

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fc5dcd..39f3c47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,19 +11,19 @@ ADD_LIBRARY(lib STATIC ${SOURCES})
 
 LINK_LIBRARIES(lib)
 
-ADD_EXECUTABLE(test_base32  ${PROJECT_SOURCE_DIR}/src/test/test_base32.c)
-ADD_EXECUTABLE(test_base64  ${PROJECT_SOURCE_DIR}/src/test/test_base64.c)
-ADD_EXECUTABLE(test_crypt   ${PROJECT_SOURCE_DIR}/src/test/test_crypt.c)
-ADD_EXECUTABLE(test_endian  ${PROJECT_SOURCE_DIR}/src/test/test_endian.c)
-ADD_EXECUTABLE(test_error   ${PROJECT_SOURCE_DIR}/src/test/test_error.c)
-ADD_EXECUTABLE(test_optget  ${PROJECT_SOURCE_DIR}/src/test/test_optget.c)
-ADD_EXECUTABLE(test_strconv ${PROJECT_SOURCE_DIR}/src/test/test_strconv.c)
+ADD_EXECUTABLE(test_base32 ${PROJECT_SOURCE_DIR}/src/test/test_base32.c)
+ADD_EXECUTABLE(test_base64 ${PROJECT_SOURCE_DIR}/src/test/test_base64.c)
+ADD_EXECUTABLE(test_crypt  ${PROJECT_SOURCE_DIR}/src/test/test_crypt.c)
+ADD_EXECUTABLE(test_endian ${PROJECT_SOURCE_DIR}/src/test/test_endian.c)
+ADD_EXECUTABLE(test_error  ${PROJECT_SOURCE_DIR}/src/test/test_error.c)
+ADD_EXECUTABLE(test_optget ${PROJECT_SOURCE_DIR}/src/test/test_optget.c)
+ADD_EXECUTABLE(test_strtou ${PROJECT_SOURCE_DIR}/src/test/test_strtou.c)
 
 ENABLE_TESTING()
-ADD_TEST(NAME test_base32  COMMAND test_base32)
-ADD_TEST(NAME test_base64  COMMAND test_base64)
-ADD_TEST(NAME test_crypt   COMMAND test_crypt)
-ADD_TEST(NAME test_endian  COMMAND test_endian)
-ADD_TEST(NAME test_error   COMMAND test_error)
-ADD_TEST(NAME test_optget  COMMAND test_optget)
-ADD_TEST(NAME test_strconv COMMAND test_strconv)
+ADD_TEST(NAME test_base32 COMMAND test_base32)
+ADD_TEST(NAME test_base64 COMMAND test_base64)
+ADD_TEST(NAME test_crypt  COMMAND test_crypt)
+ADD_TEST(NAME test_endian COMMAND test_endian)
+ADD_TEST(NAME test_error  COMMAND test_error)
+ADD_TEST(NAME test_optget COMMAND test_optget)
+ADD_TEST(NAME test_strtou COMMAND test_strtou)
diff --git a/README.md b/README.md
index a5cdf19..d8e43a0 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ OMKOV lib is a lightweight generic library to be included locally in projects.
 | error            | Error reporting functions                           |
 | mode             | Parse numeric or symbolic POSIX modes               |
 | optget           | Parse command line options                          |
+| strconv          | String conversion functions                         |
 
 ## Build Instructions
 
diff --git a/src/strconv.h b/src/strconv.h
index 11e91c8..f5c6762 100644
--- a/src/strconv.h
+++ b/src/strconv.h
@@ -1,4 +1,4 @@
-// strconv.h, version 1.0.0
+// strconv.h, version 1.1.0
 // String conversion header file for OMKOV lib
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.
@@ -35,6 +35,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 #include <stdint.h>
 
+int8_t strtoi8(const char *nptr, char **endptr, register int base);
+int16_t strtoi16(const char *nptr, char **endptr, register int base);
+int32_t strtoi32(const char *nptr, char **endptr, register int base);
+int64_t strtoi64(const char *nptr, char **endptr, register int base);
+
 uint8_t strtou8(const char *nptr, char **endptr, register int base);
 uint16_t strtou16(const char *nptr, char **endptr, register int base);
 uint32_t strtou32(const char *nptr, char **endptr, register int base);
diff --git a/src/strtoi.c b/src/strtoi.c
new file mode 100644
index 0000000..7951000
--- /dev/null
+++ b/src/strtoi.c
@@ -0,0 +1,164 @@
+// strtoi.c, version 1.1.0
+// String conversion source file for OMKOV lib
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+/*
+OMKOV Permissive Licence, version 1.0
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimers.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimers in the documentation and/or
+  other materials provided with the distribution.
+* Neither the names of the copyright holders, nor the names of its contributors
+  may be used to endorse or promote products derived from this Software without
+  specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
+HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/* Convert a string to a signed 8-bit integer */
+int8_t strtoi8(const char *nptr, char **endptr, register int base) {
+	register const char *s = nptr; register uint8_t i = 0, c; bool neg = false;
+	
+	for (; isspace(*s); ++s);
+	
+	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
+	
+	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
+		s += 2; base = 16;
+	}
+	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
+	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
+	
+	for (;; ++s) {
+		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
+		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
+		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
+		else { break; }
+		
+		if (c >= base) { break; }
+		if (i > (neg ? -INT8_MIN : INT8_MAX - c) / base) {
+			errno = ERANGE; i = neg ? INT8_MIN : INT8_MAX; goto end;
+		}
+		
+		i = i * base + c;
+	}
+	
+end:;
+	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
+}
+
+/* Convert a string to a signed 16-bit integer */
+int16_t strtoi16(const char *nptr, char **endptr, register int base) {
+	register const char *s = nptr; register uint16_t i = 0, c; bool neg = false;
+	
+	for (; isspace(*s); ++s);
+	
+	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
+	
+	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
+		s += 2; base = 16;
+	}
+	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
+	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
+	
+	for (;; ++s) {
+		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
+		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
+		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
+		else { break; }
+		
+		if (c >= base) { break; }
+		if (i > (neg ? -INT16_MIN : INT16_MAX - c) / base) {
+			errno = ERANGE; i = neg ? INT16_MIN : INT16_MAX; goto end;
+		}
+		
+		i = i * base + c;
+	}
+	
+end:;
+	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
+}
+
+/* Convert a string to a signed 32-bit integer */
+int32_t strtoi32(const char *nptr, char **endptr, register int base) {
+	register const char *s = nptr; register uint32_t i = 0, c; bool neg = false;
+	
+	for (; isspace(*s); ++s);
+	
+	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
+	
+	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
+		s += 2; base = 16;
+	}
+	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
+	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
+	
+	for (;; ++s) {
+		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
+		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
+		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
+		else { break; }
+		
+		if (c >= base) { break; }
+		if (i > (neg ? -INT32_MIN : INT32_MAX - c) / base) {
+			errno = ERANGE; i = neg ? INT32_MIN : INT32_MAX; goto end;
+		}
+		
+		i = i * base + c;
+	}
+	
+end:;
+	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
+}
+
+/* Convert a string to a signed 64-bit integer */
+int64_t strtoi64(const char *nptr, char **endptr, register int base) {
+	register const char *s = nptr; register uint64_t i = 0, c; bool neg = false;
+	
+	for (; isspace(*s); ++s);
+	
+	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
+	
+	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
+		s += 2; base = 16;
+	}
+	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
+	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
+	
+	for (;; ++s) {
+		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
+		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
+		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
+		else { break; }
+		
+		if (c >= base) { break; }
+		if (i > (neg ? -INT64_MIN : INT64_MAX - c) / base) {
+			errno = ERANGE; i = neg ? INT64_MIN : INT64_MAX; goto end;
+		}
+		
+		i = i * base + c;
+	}
+	
+end:;
+	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
+}
diff --git a/src/strtou.c b/src/strtou.c
index d320eef..2584dce 100644
--- a/src/strtou.c
+++ b/src/strtou.c
@@ -1,4 +1,4 @@
-// strtou.c, version 1.0.0
+// strtou.c, version 1.1.0
 // String conversion source file for OMKOV lib
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.
diff --git a/src/test/test_strconv.c b/src/test/test_strtou.c
similarity index 99%
rename from src/test/test_strconv.c
rename to src/test/test_strtou.c
index 83d9781..eb9609f 100644
--- a/src/test/test_strconv.c
+++ b/src/test/test_strtou.c
@@ -1,4 +1,4 @@
-// test_strconv.c
+// test_strtou.c
 // String conversion unit test for OMKOV lib
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.