diff --git a/README.md b/README.md index 5d0343e..6dd62e9 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ CLI utility for defining custom project initialization scripts. TODO: - [ ] Add evaluator tests. - [ ] Color output to console. -- [ ] string -> line, case insensitive - [ ] Ensure keys are alphanumeric, underscore -- [ ] sophie ## Overview diff --git a/include/string_utils.h b/include/string_utils.h index 2447ed0..e7a6d20 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -23,4 +23,23 @@ This function assumes a forward slash path separator (i.e. `/`). */ char *join(size_t n, const char *segments[static n], char sep); +/** +@brief Perform case insensitive string comparison. + +This function operates like `strcmp` except comparison ignores case. + +@param s1 + C string to be compared. +@param s2 + C string to be compared. +@return + An integral value indicating the relationship between the strings: + - `< 0`: the first character (converted uppercase) that does not match has a + lower value in @p s1 than in @p s2. + - `= 0`: the contents of both strings are equal. + - `> 0`: the first character (converted uppercase) that does not match has a + greater value in @p s1 than in @p s2. +*/ +int strcmp_ci(const char *s1, const char *s2); + #endif /* _BOOTSTRAP_STRING_UTILS_H */ diff --git a/src/string_utils.c b/src/string_utils.c index 897132c..332d81a 100644 --- a/src/string_utils.c +++ b/src/string_utils.c @@ -1,6 +1,8 @@ #include "string_utils.h" #include +#include +#include #include char *join(size_t n, const char *segments[static n], char sep) { @@ -26,3 +28,20 @@ char *join(size_t n, const char *segments[static n], char sep) { return joined; } + +int strcmp_ci(const char *s1, const char *s2) { + int i = 0; + size_t s1_len = strlen(s1); + size_t s2_len = strlen(s2); + for (; i < (s1_len < s2_len ? s1_len : s2_len); ++i) { + if (toupper(s1[i]) < toupper(s2[i])) { + return -1; + } else if (toupper(s1[i]) > toupper(s2[i])) { + return 1; + } + } + if (s1_len == s2_len) { + return 0; + } + return s1_len < s2_len ? -1 : 1; +} diff --git a/src/validator.c b/src/validator.c index 1ddd491..477bfb4 100644 --- a/src/validator.c +++ b/src/validator.c @@ -1,6 +1,6 @@ #include "validator.h" -#include +#include "string_utils.h" static struct Error *read_field(const cJSON *const field, struct Field **out) { if (!cJSON_IsObject(field)) { @@ -27,7 +27,7 @@ static struct Error *read_field(const cJSON *const field, struct Field **out) { goto cleanup; } - if (strcmp(type->valuestring, "STRING") == 0) { + if (strcmp_ci(type->valuestring, "text") == 0) { (*out)->type = FT_TEXT; } else { error = ERROR_NEW( diff --git a/test/test.c b/test/test.c index a6dddd8..55abe74 100644 --- a/test/test.c +++ b/test/test.c @@ -26,6 +26,7 @@ int main(int argc, char *argv[]) { sput_enter_suite("string_utils"); sput_run_test(test_join_single); sput_run_test(test_join_multiple); + sput_run_test(test_strcmp_ci); sput_enter_suite("parser"); sput_run_test(test_parser_missing); @@ -37,6 +38,7 @@ int main(int argc, char *argv[]) { sput_run_test(test_validator_field_not_object); sput_run_test(test_validator_field_type_invalid); sput_run_test(test_validator_field_type_unknown); + sput_run_test(test_validator_valid_type_ci); sput_run_test(test_validator_field_prompt_invalid); sput_run_test(test_validator_valid); diff --git a/test/test_string_utils.h b/test/test_string_utils.h index 694fa49..42f752a 100644 --- a/test/test_string_utils.h +++ b/test/test_string_utils.h @@ -18,4 +18,14 @@ static void test_join_multiple() { free(joined); } +static void test_strcmp_ci() { + const char *a1 = "aBcD"; + const char *a2 = "AbCd"; + sput_fail_unless(strcmp_ci(a1, a2) == 0, "strcmp_ci == 0"); + const char *b1 = "aBcDe"; + const char *b2 = "AbCd"; + sput_fail_unless(strcmp_ci(b1, b2) > 0, "strcmp_ci > 0"); + sput_fail_unless(strcmp_ci(b2, b1) < 0, "strcmp_ci < 0"); +} + #endif /* _BOOTSTRAP_TEST_STRING_UTILS */ diff --git a/test/test_validator.h b/test/test_validator.h index 1de69ed..9aaf0f2 100644 --- a/test/test_validator.h +++ b/test/test_validator.h @@ -88,11 +88,27 @@ static void test_validator_field_type_unknown() { test_validator_teardown(fixture); } +static void test_validator_valid_type_ci() { + struct TestValidatorFixture *fixture = test_validator_setup( + "{" + " \"key\": {" + " \"type\": \"tExT\"," + " \"prompt\": \"What value for key?\"" + " }" + "}" + ); + + struct Error *error = validate_spec_json(fixture->parsed, &fixture->prompts); + sput_fail_unless(error == 0, "valid"); + + test_validator_teardown(fixture); +} + static void test_validator_field_prompt_invalid() { struct TestValidatorFixture *fixture = test_validator_setup( "{" " \"key\": {" - " \"type\": \"STRING\"," + " \"type\": \"text\"," " \"prompt\": 2" " }" "}" @@ -111,7 +127,7 @@ static void test_validator_valid() { struct TestValidatorFixture *fixture = test_validator_setup( "{" " \"key\": {" - " \"type\": \"STRING\"," + " \"type\": \"text\"," " \"prompt\": \"What value for key?\"" " }" "}"