summaryrefslogtreecommitdiff
path: root/32_kvs
diff options
context:
space:
mode:
authorHaidong Ji2022-04-15 15:51:30 -0500
committerHaidong Ji2022-04-15 15:51:30 -0500
commit442a49ad5a48d417345959b903ae6a6d32d55759 (patch)
treec7127bb497e5e439018b1915e0136eec2c9cb124 /32_kvs
Great C programming funHEADmaster
Excellent fundamentals and displine training, many tools and techniques exercises: gdb, emacs, valgrind, git
Diffstat (limited to '32_kvs')
-rw-r--r--32_kvs/Makefile12
-rw-r--r--32_kvs/README118
-rw-r--r--32_kvs/README~118
-rw-r--r--32_kvs/grade.txt19
-rw-r--r--32_kvs/kv.c87
-rw-r--r--32_kvs/kv.c~81
-rw-r--r--32_kvs/kv.h26
-rw-r--r--32_kvs/kv.obin0 -> 58936 bytes
-rwxr-xr-x32_kvs/kv_testbin0 -> 54408 bytes
-rw-r--r--32_kvs/kv_test.c17
-rw-r--r--32_kvs/kv_test.obin0 -> 54280 bytes
-rw-r--r--32_kvs/test.old6
-rw-r--r--32_kvs/test.txt3
13 files changed, 487 insertions, 0 deletions
diff --git a/32_kvs/Makefile b/32_kvs/Makefile
new file mode 100644
index 0000000..38f5d54
--- /dev/null
+++ b/32_kvs/Makefile
@@ -0,0 +1,12 @@
+CFLAGS=-Wall -Werror -std=gnu99 -pedantic -ggdb3
+OBJS=kv_test.o kv.o
+PROGRAM=kv_test
+
+$(PROGRAM): $(OBJS)
+ gcc $(CFLAGS) -o $@ $(OBJS)
+
+%.o: %.c kv.h
+ gcc -c $(CFLAGS) $<
+
+clean:
+ rm -f $(OBJS) $(PROGRAM) *~
diff --git a/32_kvs/README b/32_kvs/README
new file mode 100644
index 0000000..35b0a18
--- /dev/null
+++ b/32_kvs/README
@@ -0,0 +1,118 @@
+For the next 4 problems, you will be doing one slightly larger program, which
+we will cut up into 4 discretely testable pieces.
+
+The big picture is that your program will read two types of input files.
+The first type of input file (which your program will read one of) will have the format:
+
+key1=value1
+key2=value2
+....
+keyN=valueN
+
+That is, it might say
+
+Jean Luc Picard=Captain
+Will Riker=Commander
+Beverly Crusher=Commander
+Data=Lt. Commander
+Geordi LaForge=Lt. Commander
+Worf=Lt. Commander
+Deanna Troi=Commander
+
+Note that the division between the key and the value is the first equals sign (the
+values could have = in them, but the keys cannot. So a=b=c, would have a key of a, and
+a value of b=c).
+
+The second type of input file will contain a list of lines (which will typically match
+the keys from the first input file). Your program will read one or more of this
+type of file. For example, it might contain:
+
+Jean Luc Picard
+Will Riker
+Worf
+Deanna Troi
+Q
+
+For each such input file that your program reads, it will print out the counts
+of the values for the corresponding keys (or <unknown> for anything that did not
+match any known key from the first input file). E.g. given the above to input files,
+it would print to the corresponding output file (which will be named the same
+as the input file, but with ".count" appended to the name).
+
+Captain: 1
+Commander: 2
+Lt. Commander: 1
+<unknown> : 1
+
+
+
+
+In thinking about our program, we might come up with the following
+generalized high-level algorithm:
+
+ //read the key/value pairs from the file named by argv[1] (call the result kv)
+ //count from 2 to argc (call the number you count i)
+ //count the values that appear in the file named by argv[i], using kv as the key/value pair
+ // (call this result c)
+ //compute the output file name from argv[i] (call this outName)
+ //open the file named by outName (call that f)
+ //print the counts from c into the FILE f
+ //close f
+ //free the memory for outName and c
+ //free the memory for kv
+
+This high-level algorithm suggests many functions which we can split our task into.
+We will cut them up into 4 groups to make the 4 problems of this assignment:
+
+The first step (this problem):
+ - read the key/value pairs from a file
+ - free the memory for the key/value pairs
+
+The second step (next problem):
+ - compute the output file name
+
+The third step (problem after that):
+ - print the counts to a file
+ - free the memory for the counts
+
+The fourth step (the problem after that):
+ - compute the counts of values that appear in a particular input file
+
+Each subsequent problem will have more details about it.
+
+For this particular problem, you will need to:
+
+ - read the key/value pairs from a file
+ - free the memory for the key/value pairs
+
+To start with this problem, you are going to want to define two structs, in the
+file kv.h. The first one (struct _kvpair_t) should define the structure for
+one key/value pair. The second should define the structure for an
+array of key/value pairs (hint: you will want to include the length of the
+array in this structure).
+
+Now you will want to write the four functions in kv.c.
+
+In readKVs, you will want to open the file, read the lines of text, split them into
+key/value pairs, add the resulting pairs to an array (hint: realloc it to make it larger
+each time), close the file, and return the kvarray_t * that has your array.
+
+Remember that you will want to abstract out complex steps into functions (you should
+see at least 2 pieces to naturally pull out into their own functions).
+
+Next, you will write freeKVs, which should free all the memory allocated by readKVs.
+That is, freeKVs(readKVs(filename)) should not leak any memory.
+
+Third, write printKVs which should take a kvarray_t *, and print out
+
+ "key = '%s' value = '%s'\n"
+for each key/value pair in the array, with the first %s being whatever the key is,
+and the second being whatever value (e.g., key = 'Jean Luc Picard' value = 'Captain').
+
+Finally, write the lookupValue function, which takes a kvarray_t * and a char * (string).
+The char * that is passed in represents a key. This function searches the kvarray_t
+for a matching key, and if found, returns the corresponding value. If no match is found,
+this function returns NULL.
+
+Once you complete these functions, test them using the main in kv_test.c before
+proceeding to the next problem.
diff --git a/32_kvs/README~ b/32_kvs/README~
new file mode 100644
index 0000000..b4ee3c6
--- /dev/null
+++ b/32_kvs/README~
@@ -0,0 +1,118 @@
+For the next 4 problems, you will be doing one slightly larger program, which
+we will cut up into 4 discretely testable pieces.
+
+The big picture it that your program will read two types of input files.
+The first type of input file (which your program will read one of) will have the format:
+
+key1=value1
+key2=value2
+....
+keyN=valueN
+
+That is, it might say
+
+Jean Luc Picard=Captain
+Will Riker=Commander
+Beverly Crusher=Commander
+Data=Lt. Commander
+Geordi LaForge=Lt. Commander
+Worf=Lt. Commander
+Deanna Troi=Commander
+
+Not that the division between the key and the value is the first equals sign (the
+values could have = in them, but the keys cannot. So a=b=c, would have a key of a, and
+a value of b=c).
+
+The second type of input file will contain a list of lines (which will typically match
+the keys from the first input file). Your program will read one or more of this
+type of file. For example, it might contain:
+
+Jean Luc Picard
+Will Riker
+Worf
+Deanna Troi
+Q
+
+For each such input file that your program reads, it will print out the counts
+of the values for the corresponding keys (or <unknown> for anything that did not
+match any known key from the first input file). E.g. given the above to input files,
+it would print to the corresponding output file (which will be named the same
+as the input file, but with ".count" appended to the name).
+
+Captain: 1
+Commander: 2
+Lt. Commander: 1
+<unknown> : 1
+
+
+
+
+In thinking about our program, we might come up with the following
+generalized high-level algorithm:
+
+ //read the key/value pairs from the file named by argv[1] (call the result kv)
+ //count from 2 to argc (call the number you count i)
+ //count the values that appear in the file named by argv[i], using kv as the key/value pair
+ // (call this result c)
+ //compute the output file name from argv[i] (call this outName)
+ //open the file named by outName (call that f)
+ //print the counts from c into the FILE f
+ //close f
+ //free the memory for outName and c
+ //free the memory for kv
+
+This high-level algorithm suggests many functions which we can split our task into.
+We will cut them up into 4 groups to make the 4 problems of this assignment:
+
+The first step (this problem):
+ - read the key/value pairs from a file
+ - free the memory for the key/value pairs
+
+The second step (next problem):
+ - compute the output file name
+
+The third step (problem after that):
+ - print the counts to a file
+ - free the memory for the counts
+
+The fourth step (the problem after that):
+ - compute the counts of values that appear in a particular input file
+
+Each subsequent problem will have more details about it.
+
+For this particular problem, you will need to:
+
+ - read the key/value pairs from a file
+ - free the memory for the key/value pairs
+
+To start with this problem, you are going to want to define two structs, in the
+file kv.h. The first one (struct _kvpair_t) should define the structure for
+one key/value pair. The second should define the structure for an
+array of key/value pairs (hint: you will want to include the length of the
+array in this structure).
+
+Now you will want to write the four functions in kv.c.
+
+In readKVs, you will want to open the file, read the lines of text, split them into
+key/value pairs, add the resulting pairs to an array (hint: realloc it to make it larger
+each time), close the file, and return the kvarray_t * that has your array.
+
+Remember that you will want to abstract out complex steps into functions (you should
+see at least 2 pieces to naturally pull out into their own functions).
+
+Next, you will write freeKVs, which should free all the memory allocated by readKVs.
+That is, freeKVs(readKVs(filename)) should not leak any memory.
+
+Third, write printKVs which should take a kvarray_t *, and print out
+
+ "key = '%s' value = '%s'\n"
+for each key/value pair in the array, with the first %s being whatever the key is,
+and the second being whatever value (e.g., key = 'Jean Luc Picard' value = 'Captain').
+
+Finally, write the lookupValue function, which takes a kvarray_t * and a char * (string).
+The char * that is passed in represents a key. This function searches the kvarray_t
+for a matching key, and if found, returns the corresponding value. If no match is found,
+this function returns NULL.
+
+Once you complete these functions, test them using the main in kv_test.c before
+proceeding to the next problem.
diff --git a/32_kvs/grade.txt b/32_kvs/grade.txt
new file mode 100644
index 0000000..241c564
--- /dev/null
+++ b/32_kvs/grade.txt
@@ -0,0 +1,19 @@
+Grading at Fri 24 Dec 2021 08:54:52 PM UTC
+Attempting to compile:
+#################################################
+testcase1:
+Your output is correct
+ - Valgrind was clean (no errors, no memory leaks)
+valgrind was clean
+#################################################
+testcase2:
+Your output is correct
+ - Valgrind was clean (no errors, no memory leaks)
+valgrind was clean
+#################################################
+testcase3:
+Your output is correct
+ - Valgrind was clean (no errors, no memory leaks)
+valgrind was clean
+
+Overall Grade: A
diff --git a/32_kvs/kv.c b/32_kvs/kv.c
new file mode 100644
index 0000000..00958c5
--- /dev/null
+++ b/32_kvs/kv.c
@@ -0,0 +1,87 @@
+#include "kv.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *splitLine2KV(char *line, const char *delim) {
+ char *v = strstr(line, delim);
+
+ if (v == NULL)
+ return NULL;
+
+ *v = '\0';
+
+ v = v + strlen(delim);
+ strtok(v, "\n");
+
+ char *ans = malloc((strlen(v) + 1) * sizeof(*ans));
+ strcpy(ans, v);
+ // return v + strlen(delim);
+ return ans;
+}
+
+kvarray_t *readKVs(const char *fname) {
+ FILE *f = fopen(fname, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Could not open file\n");
+ return NULL;
+ }
+
+ kvarray_t *kvArray = malloc(sizeof(*kvArray));
+ kvArray->kvarray = NULL;
+ kvArray->kvarrayLength = 0;
+ char *line = NULL;
+ size_t sz = 0;
+ int i = 0;
+ char *v = NULL;
+
+ while (getline(&line, &sz, f) >= 0) {
+ v = splitLine2KV(line, "=");
+ if (v) {
+ kvpair_t *kvPair = malloc(sizeof(*kvPair));
+ kvPair->key = malloc((strlen(line) + 1) * sizeof(kvPair->key));
+ kvPair->value = malloc((strlen(v) + 1) * sizeof(kvPair->value));
+ strcpy(kvPair->key, line);
+ strcpy(kvPair->value, v);
+ kvArray->kvarray = realloc(kvArray->kvarray, (i + 1) * sizeof(kvpair_t));
+ kvArray->kvarray[i] = *kvPair;
+ i++;
+ kvArray->kvarrayLength = i;
+ free(kvPair);
+ }
+ free(v);
+ }
+ free(line);
+
+ if (fclose(f) != 0) {
+ fprintf(stderr, "Could not close file\n");
+ return NULL;
+ }
+
+ return kvArray;
+}
+
+void freeKVs(kvarray_t *pairs) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ free(pairs->kvarray[i].key);
+ free(pairs->kvarray[i].value);
+ }
+ free(pairs->kvarray);
+ free(pairs);
+}
+
+void printKVs(kvarray_t *pairs) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ printf("key = '%s' value = '%s'\n", pairs->kvarray[i].key,
+ pairs->kvarray[i].value);
+ }
+}
+
+char *lookupValue(kvarray_t *pairs, const char *key) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ if (strcmp(pairs->kvarray[i].key, key) == 0) {
+ return pairs->kvarray[i].value;
+ }
+ }
+ return NULL;
+}
diff --git a/32_kvs/kv.c~ b/32_kvs/kv.c~
new file mode 100644
index 0000000..d215207
--- /dev/null
+++ b/32_kvs/kv.c~
@@ -0,0 +1,81 @@
+#include "kv.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *splitLine2KV(char *line, const char *delim) {
+ char *v = strstr(line, delim);
+
+ if (v == NULL)
+ return NULL;
+
+ *v = '\0';
+ return v + strlen(delim);
+}
+
+kvarray_t *readKVs(const char *fname) {
+ FILE *f = fopen(fname, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Could not open file\n");
+ return NULL;
+ }
+
+ kvarray_t *kvArray = malloc(sizeof(*kvArray));
+ kvArray->kvarray = NULL;
+ char *line = NULL;
+ size_t sz = 0;
+ int i = 0;
+
+ while (getline(&line, &sz, f) >= 0) {
+ char *v;
+ v = splitLine2KV(line, "=");
+ if (v) {
+ char *value = malloc((strlen(v) + 1) * sizeof(*value));
+ strcpy(value, strtok(v, "\n"));
+ char *key = malloc((strlen(line) + 1) * sizeof(*key));
+ strcpy(key, line);
+
+ kvpair_t *kvPair = malloc(sizeof(kvPair));
+ kvPair->key = key;
+ kvPair->value = value;
+ kvArray->kvarray = realloc(kvArray->kvarray, (i + 1) * sizeof(kvpair_t));
+ kvArray->kvarray[i] = *kvPair;
+ free(kvPair);
+ i++;
+ kvArray->kvarrayLength = i;
+ }
+ }
+ free(line);
+
+ if (fclose(f) != 0) {
+ fprintf(stderr, "Could not close file\n");
+ return NULL;
+ }
+
+ return kvArray;
+}
+
+void freeKVs(kvarray_t *pairs) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ free(pairs->kvarray[i].key);
+ free(pairs->kvarray[i].value);
+ }
+ free(pairs->kvarray);
+ free(pairs);
+}
+
+void printKVs(kvarray_t *pairs) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ printf("key = '%s' value = '%s'\n", pairs->kvarray[i].key,
+ pairs->kvarray[i].value);
+ }
+}
+
+char *lookupValue(kvarray_t *pairs, const char *key) {
+ for (int i = 0; i < pairs->kvarrayLength; i++) {
+ if (strcmp(pairs->kvarray[i].key, key) == 0) {
+ return pairs->kvarray[i].value;
+ }
+ }
+ return NULL;
+}
diff --git a/32_kvs/kv.h b/32_kvs/kv.h
new file mode 100644
index 0000000..51ccbb1
--- /dev/null
+++ b/32_kvs/kv.h
@@ -0,0 +1,26 @@
+#ifndef __KV_H__
+#define __KV_H__
+
+
+struct _kvpair_t {
+ char * key;
+ char * value;
+};
+typedef struct _kvpair_t kvpair_t;
+
+struct _kvarray_t {
+ kvpair_t * kvarray;
+ int kvarrayLength;
+};
+typedef struct _kvarray_t kvarray_t;
+
+
+kvarray_t * readKVs(const char * fname);
+
+void freeKVs(kvarray_t * pairs);
+
+void printKVs(kvarray_t * pairs);
+
+char * lookupValue(kvarray_t * pairs, const char * key);
+
+#endif
diff --git a/32_kvs/kv.o b/32_kvs/kv.o
new file mode 100644
index 0000000..017f5db
--- /dev/null
+++ b/32_kvs/kv.o
Binary files differ
diff --git a/32_kvs/kv_test b/32_kvs/kv_test
new file mode 100755
index 0000000..3aa5b6e
--- /dev/null
+++ b/32_kvs/kv_test
Binary files differ
diff --git a/32_kvs/kv_test.c b/32_kvs/kv_test.c
new file mode 100644
index 0000000..5532512
--- /dev/null
+++ b/32_kvs/kv_test.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "kv.h"
+
+#define NUM_LOOKUPS 5
+int main(void) {
+ kvarray_t * array = readKVs("test.txt");
+ printf("Printing all keys\n\n");
+ printKVs(array);
+ char *tests[NUM_LOOKUPS] = {"banana", "grapes", "cantaloupe", "lettuce", "orange"};
+ for (int i = 0; i < NUM_LOOKUPS; i++) {
+ printf("lookupValue('%s')=%s\n", tests[i], lookupValue(array,tests[i]));
+ }
+ freeKVs(array);
+ return EXIT_SUCCESS;
+}
diff --git a/32_kvs/kv_test.o b/32_kvs/kv_test.o
new file mode 100644
index 0000000..458acf1
--- /dev/null
+++ b/32_kvs/kv_test.o
Binary files differ
diff --git a/32_kvs/test.old b/32_kvs/test.old
new file mode 100644
index 0000000..782743e
--- /dev/null
+++ b/32_kvs/test.old
@@ -0,0 +1,6 @@
+apple=red
+banana=yellow
+orange=orange
+grapes=purple
+carrot=orange
+eggplant=purple
diff --git a/32_kvs/test.txt b/32_kvs/test.txt
new file mode 100644
index 0000000..c812bb6
--- /dev/null
+++ b/32_kvs/test.txt
@@ -0,0 +1,3 @@
+a
+bc
+df