reusable string util

This commit is contained in:
rusefillc 2023-08-08 23:11:37 -04:00
parent 8800977c78
commit 28a7376a84
4 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,23 @@
#pragma once
#define ATOI_ERROR_CODE 311223344
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define TO_LOWER(x) (((x)>='A' && (x)<='Z') ? (x) - 'A' + 'a' : (x))
// todo: do we even need? does 'strlen' just work like we use it in cli_registry?
uint32_t efiStrlen(const char *param);
int indexOf(const char *string, char ch);
bool strEqualCaseInsensitive(const char *str1, const char *str2);
bool strEqual(const char *str1, const char *str2);
int atoi(const char *string);
float atoff(const char *string);
#ifdef __cplusplus
}
#endif /* __cplusplus */

122
util/src/efistringutil.cpp Normal file
View File

@ -0,0 +1,122 @@
#include <cstring>
#include <cstdint>
#include <math.h>
#include <rusefi/efistringutil.h>
#include <rusefi/math.h>
uint32_t efiStrlen(const char *param) {
const char *s;
for (s = param; *s; ++s)
;
return (s - param);
}
int indexOf(const char *string, char ch) {
// a standard function for this is strnchr?
// todo: on the other hand MISRA wants us not to use standard headers
int len = efiStrlen(string);
for (int i = 0; i < len; i++) {
if (string[i] == ch) {
return i;
}
}
return -1;
}
// string to integer
int atoi(const char *string) {
int len = strlen(string);
if (len == 0) {
return -ATOI_ERROR_CODE;
}
if (string[0] == '-') {
return -atoi(string + 1);
}
int result = 0;
for (int i = 0; i < len; i++) {
char ch = string[i];
if (ch < '0' || ch > '9') {
if (i > 0) {
break;
} else {
return ATOI_ERROR_CODE;
}
}
int c = ch - '0';
result = result * 10 + c;
}
return result;
}
bool strEqualCaseInsensitive(const char *str1, const char *str2) {
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2) {
return false;
}
for (int i = 0; i < len1; i++)
if (TO_LOWER(str1[i]) != TO_LOWER(str2[i]))
return false;
return true;
}
bool strEqual(const char *str1, const char *str2) {
// todo: there must be a standard function?!
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2) {
return false;
}
for (int i = 0; i < len1; i++)
if (str1[i] != str2[i])
return false;
return true;
}
/**
* string to float. NaN input is supported
*
* @return NAN in case of invalid string
* todo: explicit value for error code? probably not, NaN is only returned in case of an error
*/
float atoff(const char *param) {
static char todofixthismesswithcopy[100];
uint32_t totallen = strlen(param);
if (totallen > sizeof(todofixthismesswithcopy) - 1)
return (float) NAN;
strcpy(todofixthismesswithcopy, param);
char *string = todofixthismesswithcopy;
if (indexOf(string, 'n') != -1 || indexOf(string, 'N') != -1) {
return (float) NAN;
}
// todo: is there a standard function?
// unit-tested by 'testMisc()'
int dotIndex = indexOf(string, '.');
if (dotIndex == -1) {
// just an integer
int result = atoi(string);
if (absI(result) == ATOI_ERROR_CODE)
return (float) NAN;
return (float) result;
}
// todo: this needs to be fixed
string[dotIndex] = 0;
int integerPart = atoi(string);
if (absI(integerPart) == ATOI_ERROR_CODE)
return (float) NAN;
string += (dotIndex + 1);
int decimalLen = strlen(string);
int decimal = atoi(string);
if (absI(decimal) == ATOI_ERROR_CODE)
return (float) NAN;
float divider = 1.0;
// todo: reuse 'pow10' function which we have anyway
for (int i = 0; i < decimalLen; i++) {
divider = divider * 10.0;
}
return integerPart + decimal / divider;
}

View File

@ -0,0 +1,8 @@
#include <gtest/gtest.h>
#include <rusefi/efistringutil.h>
TEST(Util_String, equalsIgnoreCase) {
ASSERT_FALSE(strEqualCaseInsensitive("a", "b"));
ASSERT_TRUE(strEqualCaseInsensitive("a", "A"));
}

View File

@ -3,12 +3,14 @@ RUSEFI_LIB_INC += $(RUSEFI_LIB)/util/include
RUSEFI_LIB_CPP += \
$(RUSEFI_LIB)/util/src/util_dummy.cpp \
$(RUSEFI_LIB)/util/src/crc.cpp \
$(RUSEFI_LIB)/util/src/efistringutil.cpp \
$(RUSEFI_LIB)/util/src/fragments.cpp \
$(RUSEFI_LIB)/util/src/math.cpp \
RUSEFI_LIB_CPP_TEST += \
$(RUSEFI_LIB)/util/test/test_arrays.cpp \
$(RUSEFI_LIB)/util/test/test_crc.cpp \
$(RUSEFI_LIB)/util/test/test_efistringutil.cpp \
$(RUSEFI_LIB)/util/test/test_fragments.cpp \
$(RUSEFI_LIB)/util/test/test_interpolation.cpp \
$(RUSEFI_LIB)/util/test/test_scaled.cpp \