aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/str.h1
-rw-r--r--lib/str.c41
-rw-r--r--lib/user_input.c73
-rw-r--r--tests/framework.h1
-rw-r--r--tests/test_str_strdup_array.c30
5 files changed, 92 insertions, 54 deletions
diff --git a/include/str.h b/include/str.h
index 5e6d30d..468f674 100644
--- a/include/str.h
+++ b/include/str.h
@@ -33,5 +33,6 @@ int isempty(char *sptr);
int isquoted(char *sptr);
char *normalize_space(char *s);
char **strdup_array(char **array);
+int strcmp_array(const char **a, const char **b);
#endif //SPM_STR_H
diff --git a/lib/str.c b/lib/str.c
index 5bf95ec..9b5b201 100644
--- a/lib/str.c
+++ b/lib/str.c
@@ -776,3 +776,44 @@ char **strdup_array(char **array) {
return result;
}
+
+/**
+ * Compare two arrays of strings
+ *
+ * `a` and/or `b` may be `NULL`. You should test for `NULL` in advance if _your_ program considers this an error condition.
+ *
+ * @param a array of strings
+ * @param b array of strings
+ * @return 0 = identical
+ */
+int strcmp_array(const char **a, const char **b) {
+ size_t a_len = 0;
+ size_t b_len = 0;
+
+ // This could lead to false-positives depending on what the caller plans to achieve
+ if (a == NULL && b == NULL) {
+ return 0;
+ } else if (a == NULL) {
+ return -1;
+ } else if (b == NULL) {
+ return 1;
+ }
+
+ // Get length of arrays
+ for (a_len = 0; a[a_len] != NULL; a_len++);
+ for (b_len = 0; b[b_len] != NULL; b_len++);
+
+ // Check lengths are equal
+ if (a_len < b_len) return (int)(b_len - a_len);
+ else if (a_len > b_len) return (int)(a_len - b_len);
+
+ // Compare strings in the arrays returning the total difference in bytes
+ int result = 0;
+ for (size_t ai = 0, bi = 0 ;a[ai] != NULL || b[bi] != NULL; ai++, bi++) {
+ int status = 0;
+ if ((status = strcmp(a[ai], b[bi]) != 0)) {
+ result += status;
+ }
+ }
+ return result;
+}
diff --git a/lib/user_input.c b/lib/user_input.c
index 3f358fa..416b59f 100644
--- a/lib/user_input.c
+++ b/lib/user_input.c
@@ -1,32 +1,6 @@
#include "spm.h"
-/**
- * Basic case-insensitive interactive choice function
- * @param answer
- * @param answer_default
- * @return
- */
-int spm_user_yesno(int answer, int empty_input_is_yes) {
- int result = 0;
- answer = tolower(answer);
-
- if (answer == 'y') {
- result = 1;
- } else if (answer == 'n') {
- result = 0;
- } else {
- if (empty_input_is_yes) {
- result = 1;
- } else {
- result = -1;
- }
- }
-
- return result;
-}
-
int spm_prompt_user(const char *msg, int empty_input_is_yes) {
- int user_choice = 0;
int status_choice = 0;
char ch_yes = 'y';
char ch_no = 'n';
@@ -38,38 +12,29 @@ int spm_prompt_user(const char *msg, int empty_input_is_yes) {
}
printf("\n%s [%c/%c] ", msg, ch_yes, ch_no);
- while ((user_choice = getchar())) {
- status_choice = spm_user_yesno(user_choice, 1);
- if (status_choice == 0) { // No
- break;
- } else if (status_choice == 1) { // Yes
- break;
- } else { // Only triggers when spm_user_yesno's second argument is zero
- puts("Please answer 'y' or 'n'...");
- }
- }
- puts("");
-
- return status_choice;
-}
+ char ch[2] = {0,};
+ int input_count = 0;
+ while (scanf("%c", ch) == 1) {
+ ch[1] = '\0';
-void spm_user_yesno_test() {
- int choice;
- int status;
- while ((choice = getchar())) {
- status = spm_user_yesno(choice, 1);
- if (status == -1) {
- puts("Please answer Y or N");
+ if (input_count != 0) {
+ input_count = 0;
+ ch[0] = '\0';
continue;
}
- else if (status == 0) {
- puts("You answered no");
- break;
- }
- else if (status == 1) {
- puts("You answered yes");
- break;
+
+ if ((isempty(ch) && empty_input_is_yes != 0)) {
+ return 1;
+ } else if ((isempty(ch) && empty_input_is_yes == 0)) {
+ return 0;
+ } else if (tolower(ch[0]) == tolower(ch_yes)) { // Yes
+ return 1;
+ } else if (tolower(ch[0]) == tolower(ch_no)) { // No
+ return 0;
+ } else {
+ printf("Please answer '%c' or '%c'...\n", tolower(ch_yes), tolower(ch_no));
}
+ input_count++;
}
}
diff --git a/tests/framework.h b/tests/framework.h
index 1e5adaa..d317005 100644
--- a/tests/framework.h
+++ b/tests/framework.h
@@ -6,6 +6,7 @@
union TestValue {
const char *sptr;
char **slptr;
+ const char **cslptr;
char character;
unsigned int unsigned_integer;
signed int signed_integer;
diff --git a/tests/test_str_strdup_array.c b/tests/test_str_strdup_array.c
new file mode 100644
index 0000000..5590a74
--- /dev/null
+++ b/tests/test_str_strdup_array.c
@@ -0,0 +1,30 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: (array){%s} expected (array){%s}, returned (array){%s} \n";
+struct TestCase testCase[] = {
+ {.caseValue.slptr = (char *[]){"a", "a", "c", "d", "e", NULL}, .truthValue.slptr = (char *[]){"a", "a", "c", "d", "e", NULL}},
+ {.caseValue.slptr = (char *[]){"e", "d", "c", "b", "a", NULL}, .truthValue.slptr = (char *[]){"e", "d", "c", "b", "a", NULL}},
+ {.caseValue.slptr = (char *[]){"ha", "haha", "hahaha", "hahahaha", "hahahahaha", NULL}, .truthValue.slptr = (char *[]){"ha", "haha", "hahaha", "hahahaha", "hahahahaha", NULL}},
+ {.caseValue.slptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char **result = strdup_array(testCase[i].caseValue.slptr);
+ myassert(strcmp_array(result, testCase[i].truthValue.slptr) == 0,
+ testFmt,
+ array_to_string(testCase[i].caseValue.slptr, ", "),
+ array_to_string(testCase[i].truthValue.slptr, ", "),
+ array_to_string(result, ", "));
+
+ if (result != NULL) {
+ for (size_t r = 0; result[r] != NULL; r++) {
+ free(result[r]);
+ }
+ free(result);
+ }
+ }
+ return 0;
+} \ No newline at end of file