Use case-insensitive variant of `strcmp`.
parent
6f77c400e9
commit
0fc476ceed
|
@ -5,9 +5,7 @@ CLI utility for defining custom project initialization scripts.
|
||||||
TODO:
|
TODO:
|
||||||
- [ ] Add evaluator tests.
|
- [ ] Add evaluator tests.
|
||||||
- [ ] Color output to console.
|
- [ ] Color output to console.
|
||||||
- [ ] string -> line, case insensitive
|
|
||||||
- [ ] Ensure keys are alphanumeric, underscore
|
- [ ] Ensure keys are alphanumeric, underscore
|
||||||
- [ ] sophie
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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 */
|
#endif /* _BOOTSTRAP_STRING_UTILS_H */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
char *join(size_t n, const char *segments[static n], char sep) {
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "validator.h"
|
#include "validator.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include "string_utils.h"
|
||||||
|
|
||||||
static struct Error *read_field(const cJSON *const field, struct Field **out) {
|
static struct Error *read_field(const cJSON *const field, struct Field **out) {
|
||||||
if (!cJSON_IsObject(field)) {
|
if (!cJSON_IsObject(field)) {
|
||||||
|
@ -27,7 +27,7 @@ static struct Error *read_field(const cJSON *const field, struct Field **out) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(type->valuestring, "STRING") == 0) {
|
if (strcmp_ci(type->valuestring, "text") == 0) {
|
||||||
(*out)->type = FT_TEXT;
|
(*out)->type = FT_TEXT;
|
||||||
} else {
|
} else {
|
||||||
error = ERROR_NEW(
|
error = ERROR_NEW(
|
||||||
|
|
|
@ -26,6 +26,7 @@ int main(int argc, char *argv[]) {
|
||||||
sput_enter_suite("string_utils");
|
sput_enter_suite("string_utils");
|
||||||
sput_run_test(test_join_single);
|
sput_run_test(test_join_single);
|
||||||
sput_run_test(test_join_multiple);
|
sput_run_test(test_join_multiple);
|
||||||
|
sput_run_test(test_strcmp_ci);
|
||||||
|
|
||||||
sput_enter_suite("parser");
|
sput_enter_suite("parser");
|
||||||
sput_run_test(test_parser_missing);
|
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_not_object);
|
||||||
sput_run_test(test_validator_field_type_invalid);
|
sput_run_test(test_validator_field_type_invalid);
|
||||||
sput_run_test(test_validator_field_type_unknown);
|
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_field_prompt_invalid);
|
||||||
sput_run_test(test_validator_valid);
|
sput_run_test(test_validator_valid);
|
||||||
|
|
||||||
|
|
|
@ -18,4 +18,14 @@ static void test_join_multiple() {
|
||||||
free(joined);
|
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 */
|
#endif /* _BOOTSTRAP_TEST_STRING_UTILS */
|
||||||
|
|
|
@ -88,11 +88,27 @@ static void test_validator_field_type_unknown() {
|
||||||
test_validator_teardown(fixture);
|
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() {
|
static void test_validator_field_prompt_invalid() {
|
||||||
struct TestValidatorFixture *fixture = test_validator_setup(
|
struct TestValidatorFixture *fixture = test_validator_setup(
|
||||||
"{"
|
"{"
|
||||||
" \"key\": {"
|
" \"key\": {"
|
||||||
" \"type\": \"STRING\","
|
" \"type\": \"text\","
|
||||||
" \"prompt\": 2"
|
" \"prompt\": 2"
|
||||||
" }"
|
" }"
|
||||||
"}"
|
"}"
|
||||||
|
@ -111,7 +127,7 @@ static void test_validator_valid() {
|
||||||
struct TestValidatorFixture *fixture = test_validator_setup(
|
struct TestValidatorFixture *fixture = test_validator_setup(
|
||||||
"{"
|
"{"
|
||||||
" \"key\": {"
|
" \"key\": {"
|
||||||
" \"type\": \"STRING\","
|
" \"type\": \"text\","
|
||||||
" \"prompt\": \"What value for key?\""
|
" \"prompt\": \"What value for key?\""
|
||||||
" }"
|
" }"
|
||||||
"}"
|
"}"
|
||||||
|
|
Loading…
Reference in New Issue