diff --git a/homework06/Makefile b/homework06/Makefile index d3e8dda..8b7bc93 100644 --- a/homework06/Makefile +++ b/homework06/Makefile @@ -13,27 +13,21 @@ all: $(TARGETS) # TODO: Add rules for libstr.a libstr.so #------------------------------------------------------------------------------- -str.o: str.c - $(CC) $(CFLAGS) -c -o $@ $< +str.o: -libstr.so: str.o - $(LD) $(LDFLAGS) -shared -o $@ $< +libstr.so: -libstr.a: str.o - $(AR) $(ARFLAGS) $@ $< +libstr.a: #------------------------------------------------------------------------------- # TODO: Add rules for trit.dynamic trit.static #------------------------------------------------------------------------------- -trit.o: trit.c - $(CC) $(CFLAGS) -c -o $@ $< +trit.o: -trit.dynamic: trit.o - $(LD) $(LDFLAGS) -o $@ $< -lstr +trit.dynamic: -trit.static: trit.o libstr.a - $(LD) -o $@ $< libstr.a +trit.static: #------------------------------------------------------------------------------- # DO NOT MODIFY BELOW diff --git a/homework06/str.c b/homework06/str.c index 68d2d08..c05daa3 100644 --- a/homework06/str.c +++ b/homework06/str.c @@ -5,7 +5,6 @@ #include #include #include -#include /* Functions */ @@ -14,27 +13,17 @@ * @param s String to convert * @param w Pointer to buffer that holds result of conversion **/ - void str_lower(const char *s, char *w) { - while (*s) { - *w = tolower(*s); - s++; - w++; - } - *w = '\0'; - } +void str_lower(const char *s, char *w) { + // TODO +} /** * Convert string to uppercase. * @param s String to convert * @param w Pointer to buffer that holds result of conversion **/ -void str_upper(const char *s, char *w) { - while (*s) { - *w = toupper(*s); - s++; - w++; - } - *w = '\0'; +void str_upper(const char *s, char *w) { + // TODO } /** @@ -42,52 +31,18 @@ void str_upper(const char *s, char *w) { * @param s String to convert * @param w Pointer to buffer that holds result of conversion **/ -void str_title(const char *s, char *w) { - if (*s) { - *w = toupper(*s); - w++; - s++; - while (*s) { - if (!isalpha(*(s - 1))) { - *w = toupper(*s); - } else { - *w = tolower(*s); - } - s++; - w++; - } - } - *w = '\0'; +void str_title(const char *s, char *w) { + // TODO } -void str_rstrip(const char *s, const char *chars, char *w) { - // Safety checks - if (!s || !w) return; - - bool strip_chars[256] = {0}; - const unsigned char *p = (const unsigned char *)s; - size_t length = 0; - - // Build lookup table - if (!chars) { - // Strip standard whitespace - strip_chars[' '] = true; - strip_chars['\t'] = true; - strip_chars['\n'] = true; - } else { - for (; *chars; chars++) - strip_chars[(unsigned char)*chars] = true; - } - - // Find string length and last non-stripped character - while (*p) p++; - while (p > (const unsigned char *)s && strip_chars[*(p-1)]) - p--; - - // Calculate length and copy - length = p - (const unsigned char *)s; - memcpy(w, s, length); - w[length] = '\0'; +/** + * Strip characters from back of string (if present). + * @param s String to strip + * @param chars Characters to strip (if NULL, then all whitespace) + * @param w Pointer to buffer that holds result of strip + **/ +void str_rstrip(const char *s, const char *chars, char *w) { + // TODO } /** @@ -96,24 +51,8 @@ void str_rstrip(const char *s, const char *chars, char *w) { * @param chars Characters to delete * @param w Pointer to buffer that holds result of deletion **/ -void str_delete(const char *s, const char *chars, char *w) { - bool del_chars[256] = {0}; - - // Create lookup table - while (*chars) { - del_chars[(unsigned char)*chars] = true; - chars++; - } - - // Copy non-deleted chars to w - while (*s) { - if (!del_chars[(unsigned char)*s]) { - *w = *s; - w++; - } - s++; - } - *w = '\0'; +void str_delete(const char *s, const char *chars, char *w) { + // TODO } /** @@ -123,28 +62,8 @@ void str_delete(const char *s, const char *chars, char *w) { * @param to String with corresponding translation characters * @param w Pointer to buffer that holds result of translation **/ -void str_translate(const char *s, const char *from, const char *to, char *w) { - unsigned char translate_table[256]; - int i; - - for (i = 0; i < 256; i++) { - translate_table[i] = i; - } - - // Create the translation map - while (*from && *to) { - translate_table[(unsigned char)*from] = *to; - from++; - to++; - } - - // Translate - while (*s) { - *w = translate_table[(unsigned char)*s]; - s++; - w++; - } - *w = '\0'; +void str_translate(const char *s, const char *from, const char *to, char *w) { + // TODO } /* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework06/trit.c b/homework06/trit.c index 3a55994..3a9301f 100644 --- a/homework06/trit.c +++ b/homework06/trit.c @@ -5,16 +5,15 @@ #include #include #include -#include // For isspace /* Constants */ enum { - LOWER = 1<<1, - UPPER = 1<<2, - TITLE = 1<<3, - STRIP = 1<<4, - DELETE = 1<<5, + LOWER = 1<<1, + UPPER = 0, // TODO: Modify + TITLE = 0, // TODO: Modify + STRIP = 0, // TODO: Modify + DELETE = 0, // TODO: Modify }; /* Functions */ @@ -22,100 +21,26 @@ enum { void usage(int status) { fprintf(stderr, "Usage: trit SET1 SET2\n\n"); fprintf(stderr, "Post Translation filters:\n\n"); - fprintf(stderr, " -l Convert to lowercase\n"); - fprintf(stderr, " -u Convert to uppercase\n"); - fprintf(stderr, " -t Convert to titlecase\n"); - fprintf(stderr, " -s Strip trailing whitespace\n"); - fprintf(stderr, " -d Delete letters in SET1\n"); + fprintf(stderr, " -l Convert to lowercase\n"); + fprintf(stderr, " -u Convert to uppercase\n"); + fprintf(stderr, " -t Convert to titlecase\n"); + fprintf(stderr, " -s Strip trailing whitespace\n"); + fprintf(stderr, " -d Delete letters in SET1\n"); exit(status); } void translate_stream(FILE *stream, const char *set1, const char *set2, int flags) { - char line[256]; - - while (fgets(line, sizeof(line), stream) != NULL) { - // Remove newline char if present - size_t len = strlen(line); - if (len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\0'; - } - - // Translate or delete part of string - char processed_line[1024]; - strcpy(processed_line, line); - - if (flags & DELETE) { - str_delete(processed_line, set1, line); - strcpy(processed_line, line); - set2 = ""; - } else if (set1 != NULL && set2 != NULL) { - str_translate(processed_line, set1, set2, line); - strcpy(processed_line, line); - } - - // Filters - if (flags & LOWER) { - str_lower(processed_line, line); - strcpy(processed_line, line); - } - - if (flags & UPPER) { - str_upper(processed_line, line); - strcpy(processed_line, line); - } - - if (flags & TITLE) { - str_title(processed_line, line); - strcpy(processed_line, line); - } - - if (flags & STRIP) { - str_rstrip(processed_line, " \t\r\f\v", line); // all the whitespace characters I can think of (has no newline) - strcpy(processed_line, line); - } - - printf("%s\n", processed_line); - } + // TODO } /* Main Execution */ int main(int argc, char *argv[]) { - int flags = 0; - char *set1 = NULL; - char *set2 = NULL; - int positional_args_count = 0; + // TODO: Parse command line arguments - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-l") == 0) { - flags |= LOWER; - } else if (strcmp(argv[i], "-u") == 0) { - flags |= UPPER; - } else if (strcmp(argv[i], "-t") == 0) { - flags |= TITLE; - } else if (strcmp(argv[i], "-d") == 0) { - flags |= DELETE; - } else if (strcmp(argv[i], "-s") == 0) { - flags |= STRIP; - } else if (strcmp(argv[i], "-h") == 0) { - usage(0); - } else { - positional_args_count++; - if (positional_args_count == 1) { - set1 = argv[i]; - } else if (positional_args_count == 2) { - set2 = argv[i]; - } else { - usage(1); - } - } - } - - translate_stream(stdin, set1, set2, flags); - - return 0; + // TODO: Translate standard input + return EXIT_SUCCESS; } -/* Main Execution */ /* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/Makefile b/homework07/Makefile deleted file mode 100644 index d85917a..0000000 --- a/homework07/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -CC= gcc -CFLAGS= -Wall -g -std=gnu99 -LD= gcc -LDFLAGS= -L. -TARGETS= seqit tailit - -all: $(TARGETS) - -#-------------------------------------------------------------------------------- -# TODO: Add rules for node.o, list.o, seqit.o, tailit.o, seqit, tailit -#-------------------------------------------------------------------------------- - -node.o: node.c - $(CC) $(CFLAGS) -c node.c - -list.o: list.c - $(CC) $(CFLAGS) -c list.c - -seqit.o: seqit.c - $(CC) $(CFLAGS) -c seqit.c - -tailit.o: tailit.c - $(CC) $(CFLAGS) -c tailit.c - -seqit: seqit.o list.o node.o - $(LD) $(LDFLAGS) -o seqit seqit.o list.o node.o - -tailit: tailit.o list.o node.o - $(LD) $(LDFLAGS) -o tailit tailit.o list.o node.o - -#------------------------------------------------------------------------------- -# DO NOT MODIFY BELOW -#------------------------------------------------------------------------------- - -test: - @$(MAKE) -sk test-all - -test-all: test-gitignore test-node test-list test-seqit test-tailit - -test-gitignore: - @echo "*.o" >> .gitignore - @echo "*.sh" >> .gitignore - @echo "*.unit" >> .gitignore - -node.unit: node.unit.c node.o - $(LD) $(LDFLAGS) -o node.unit node.unit.c node.o - -test-node: node.unit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework07/node.unit.sh - @chmod +x node.unit.sh - @./node.unit.sh - -list.unit: list.unit.c node.o list.o - $(LD) $(LDFLAGS) -o list.unit list.unit.c node.o list.o - -test-list: list.unit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework07/list.unit.sh - @chmod +x list.unit.sh - @./list.unit.sh - -test-seqit: seqit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework07/seqit.test.sh - @chmod +x seqit.test.sh - @./seqit.test.sh - -test-tailit: tailit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework07/tailit.test.sh - @chmod +x tailit.test.sh - @./tailit.test.sh - -clean: - @rm -f *.o *.unit *.unit.sh *.test.sh seqit tailit diff --git a/homework07/list.c b/homework07/list.c deleted file mode 100644 index e56dd6e..0000000 --- a/homework07/list.c +++ /dev/null @@ -1,83 +0,0 @@ -/* list.c: List Structure */ - -#include "list.h" - -/* List Functions */ - -/** - * Create a List structure. - * - * @return Pointer to new List structure (must be deleted later). - **/ -List * list_create() { - List *newList = calloc(1, sizeof(List)); // Use calloc to set everything to 0 - - newList->sentinel.next = &newList->sentinel; - newList->sentinel.prev = &newList->sentinel; - - return newList; -} - -/** - * Delete List structure. - * - * @param l Pointer to List structure. - * @param release Whether or not to release the string values. - **/ -void list_delete(List *l, bool release) { - Node *current = l->sentinel.next; // Start with first node after sentinel node - - while (current != &l->sentinel) { - Node *next = current->next; - node_delete(current, release); // Call node_delete and pass in release variable - current = next; - } - - free(l); -} - -/** - * Add new Value to back of List structure. - * - * @param l Pointer to List structure. - * @param v Value to add to back of List structure. - **/ -void list_append(List *l, Value v) { - Node *appNode = node_create(v, &l->sentinel, l->sentinel.prev); - - l->sentinel.prev->next = appNode; - l->sentinel.prev = appNode; - l->size++; -} - -/** - * Remove Value at specified index from List structure. - * - * @param l Pointer to List structure. - * @param index Index of Value to remove from List structure. - * - * @return Value at index in List structure (-1 if index is out of bounds). - **/ -Value list_pop(List *l, size_t index) { - if (index >= l->size) { - return (Value)-1L; - } - - // Find the node based on index - Node *current = l->sentinel.next; - for (size_t i = 0; i < index; i++) { - current = current->next; - } - - // Unlink the node - current->prev->next = current->next; - current->next->prev = current->prev; - - Value v = current->value; - node_delete(current, false); - l->size--; - - return v; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/list.h b/homework07/list.h deleted file mode 100644 index 78e51d0..0000000 --- a/homework07/list.h +++ /dev/null @@ -1,41 +0,0 @@ -/* list.h: Doubly Linked List Library */ - -#pragma once - -#include -#include -#include - -/* Value Union */ - -typedef union { - int64_t number; // Value as number - char *string; // Value as string -} Value; - -/* Node Structure */ - -typedef struct Node Node; -struct Node { - Value value; // Value - Node *next; // Pointer to next Node - Node *prev; // Pointer to previous Node -}; - -Node * node_create(Value v, Node *next, Node *prev); -void node_delete(Node *n, bool release); - -/* List Structure */ - -typedef struct { - Node sentinel; // Sentinel Node at head and tail of List - size_t size; // Number of Nodes in List -} List; - -List * list_create(); -void list_delete(List *l, bool release); - -void list_append(List *l, Value v); -Value list_pop(List *l, size_t index); - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/list.unit.c b/homework07/list.unit.c deleted file mode 100644 index b565b1c..0000000 --- a/homework07/list.unit.c +++ /dev/null @@ -1,143 +0,0 @@ -/* list.unit.c: List Structure Unit Test */ - -#include "list.h" - -#include -#include -#include -#include -#include - -/* Constants */ - -const int64_t NUMBERS[] = {5, 7, 4, -1}; -const char *STRINGS[] = {"Orange", "South Bend", "Eau Claire", NULL}; - -/* Tests */ - -int test_00_list_create() { - List *l = list_create(); - assert(l); - assert(l->sentinel.value.number == 0); - assert(l->sentinel.next == &l->sentinel); - assert(l->sentinel.prev == &l->sentinel); - assert(l->size == 0); - free(l); - return EXIT_SUCCESS; -} - -int test_01_list_delete() { - List *l0 = list_create(); - assert(l0); - list_delete(l0, false); - - List *l1 = list_create(); - assert(l1); - for (const int64_t *n = NUMBERS; *n >= 0; n++) { - l1->sentinel.next = node_create((Value)*n, l1->sentinel.next, &l1->sentinel); - l1->size++; - } - list_delete(l1, false); - - List *l2 = list_create(); - assert(l2); - for (const char **s = STRINGS; *s; s++) { - l2->sentinel.next = node_create((Value)strdup(*s), l2->sentinel.next, &l2->sentinel); - l2->size++; - } - list_delete(l2, true); - return EXIT_SUCCESS; -} - -int test_02_list_append() { - List *l1 = list_create(); - assert(l1); - for (size_t i = 0; NUMBERS[i] >= 0; i++) { - list_append(l1, (Value)NUMBERS[i]); - assert(l1->size == (i + 1)); - } - assert(l1->sentinel.next->value.number == NUMBERS[0]); - assert(l1->sentinel.next->next->value.number == NUMBERS[1]); - assert(l1->sentinel.next->next->next->value.number == NUMBERS[2]); - assert(l1->sentinel.prev->value.number == NUMBERS[2]); - assert(l1->sentinel.prev->prev->value.number == NUMBERS[1]); - assert(l1->sentinel.prev->prev->prev->value.number == NUMBERS[0]); - list_delete(l1, false); - - List *l2 = list_create(); - assert(l2); - for (size_t i = 0; STRINGS[i]; i++) { - list_append(l2, (Value)strdup(STRINGS[i])); - assert(l2->size == (i + 1)); - } - assert(strcmp(l2->sentinel.next->value.string , STRINGS[0]) == 0); - assert(strcmp(l2->sentinel.next->next->value.string , STRINGS[1]) == 0); - assert(strcmp(l2->sentinel.next->next->next->value.string, STRINGS[2]) == 0); - assert(strcmp(l2->sentinel.prev->value.string , STRINGS[2]) == 0); - assert(strcmp(l2->sentinel.prev->prev->value.string , STRINGS[1]) == 0); - assert(strcmp(l2->sentinel.prev->prev->prev->value.string, STRINGS[0]) == 0); - list_delete(l2, true); - return EXIT_SUCCESS; -} - -int test_03_list_pop() { - List *l1 = list_create(); - assert(l1); - for (size_t i = 0; NUMBERS[i] >= 0; i++) { - list_append(l1, (Value)NUMBERS[i]); - assert(l1->size == (i + 1)); - } - - Value v1 = list_pop(l1, 1); - assert(v1.number == NUMBERS[1]); - assert(l1->sentinel.next->value.number == NUMBERS[0]); - assert(l1->sentinel.next->next->value.number == NUMBERS[2]); - assert(l1->sentinel.prev->value.number == NUMBERS[2]); - assert(l1->sentinel.prev->prev->value.number == NUMBERS[0]); - assert(l1->size == 2); - - Value v2 = list_pop(l1, 1); - assert(v2.number == NUMBERS[2]); - assert(l1->sentinel.next->value.number == NUMBERS[0]); - assert(l1->sentinel.prev->value.number == NUMBERS[0]); - assert(l1->size == 1); - - Value vX= list_pop(l1, 1); - assert(vX.number == -1L); - - Value v0 = list_pop(l1, 0); - assert(v0.number == NUMBERS[0]); - assert(l1->size == 0); - - list_delete(l1, false); - return EXIT_SUCCESS; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s NUMBER\n\n", argv[0]); - fprintf(stderr, "Where NUMBER is right of the following:\n"); - fprintf(stderr, " 0 Test list_create\n"); - fprintf(stderr, " 1 Test list_delete\n"); - fprintf(stderr, " 2 Test list_append\n"); - fprintf(stderr, " 3 Test list_pop\n"); - return EXIT_FAILURE; - } - - int number = atoi(argv[1]); - int status = EXIT_FAILURE; - - switch (number) { - case 0: status = test_00_list_create(); break; - case 1: status = test_01_list_delete(); break; - case 2: status = test_02_list_append(); break; - case 3: status = test_03_list_pop(); break; - default: fprintf(stderr, "Unknown NUMBER: %d\n", number); break; - } - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/node.c b/homework07/node.c deleted file mode 100644 index 7f04932..0000000 --- a/homework07/node.c +++ /dev/null @@ -1,40 +0,0 @@ -/* node.c: Node Structure */ - -#include "list.h" - -/* Node Functions */ - -/** - * Create a Node structure. - * - * @param v Value (Number or String). - * @param next Pointer to next Node structure. - * @param prev Pointer to previous Node structure. - * - * @return Pointer to new Node structure (must be deleted later). - **/ -Node * node_create(Value v, Node *next, Node *prev) { - Node *new_node = calloc(1, sizeof(Node)); - - new_node->value = v; - new_node->next = next; - new_node->prev = prev; - - return new_node; -} - -/** - * Delete Node structure and its contents. - * - * @param n Pointer to Node structure. - * @param release Whether or not to free the string value. - **/ -void node_delete(Node *n, bool release) { - if (release) { - free(n->value.string); - } - - free(n); -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/node.unit.c b/homework07/node.unit.c deleted file mode 100644 index 7f0bfcc..0000000 --- a/homework07/node.unit.c +++ /dev/null @@ -1,83 +0,0 @@ -/* node.unit.c: Node Structure Unit Test */ - -#include "list.h" - -#include -#include -#include -#include -#include - -/* Tests */ - -int test_00_node_create() { - Value v0 = {.number = 42}; - Node *n0 = node_create(v0, NULL, NULL); - assert(n0); - assert(n0->value.number == v0.number); - assert(n0->next == NULL); - assert(n0->prev == NULL); - - Value v1 = {.string = "better now"}; - Node *n1 = node_create(v1, n0, NULL); - assert(n1); - assert(n1->value.string == v1.string); - assert(n1->next == n0); - assert(n1->prev == NULL); - - Node *n2 = node_create((Value)strdup(v1.string), n0, n1); - assert(n2); - assert(strcmp(n2->value.string, v1.string) == 0); - assert(n2->next == n0); - assert(n2->prev == n1); - - free(n0); - free(n1); - free(n2->value.string); - free(n2); - return EXIT_SUCCESS; -} - -int test_01_node_delete() { - Value v0 = {.number = 42}; - Node *n0 = node_create(v0, NULL, NULL); - assert(n0); - - Value v1 = {.string = "better now"}; - Node *n1 = node_create(v1, n0, NULL); - assert(n1); - - Node *n2 = node_create((Value)strdup(v1.string), n0, n1); - assert(n2); - - node_delete(n0, false); - node_delete(n1, false); - node_delete(n2, true); - - return EXIT_SUCCESS; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s NUMBER\n\n", argv[0]); - fprintf(stderr, "Where NUMBER is right of the following:\n"); - fprintf(stderr, " 0 Test node_create\n"); - fprintf(stderr, " 1 Test node_delete\n"); - return EXIT_FAILURE; - } - - int number = atoi(argv[1]); - int status = EXIT_FAILURE; - - switch (number) { - case 0: status = test_00_node_create(); break; - case 1: status = test_01_node_delete(); break; - default: fprintf(stderr, "Unknown NUMBER: %d\n", number); break; - } - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/seqit.c b/homework07/seqit.c deleted file mode 100644 index 418ca61..0000000 --- a/homework07/seqit.c +++ /dev/null @@ -1,74 +0,0 @@ -/* seqit.c: Print a sequence of numbers */ - -#include "list.h" - -#include -#include -#include - -/* Functions */ - -void usage(int status) { - fprintf(stderr, "Usage: seqit LAST\n"); - fprintf(stderr, " seqit FIRST LAST\n"); - fprintf(stderr, " seqit FIRST INCREMENT LAST\n"); - exit(status); -} - -List *generate_sequence(ssize_t first, ssize_t increment, ssize_t last) { - List* sequence = list_create(); - - ssize_t current = first; - if (increment > 0) { - while (current <= last) { - list_append(sequence, (Value){.number = current}); - current += increment; - } - } else { - while (current >= last) { - list_append(sequence, (Value){.number = current}); - current += increment; - } - } - - return sequence; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - // TODO: Parse command line arguments - ssize_t first = 1, increment = 1, last = 1; // Set initial values - - switch (argc) { - case 2: - last = atoll(argv[1]); - break; - case 3: - first = atoll(argv[1]); - last = atoll(argv[2]); - break; - case 4: - first = atoll(argv[1]); - increment = atoll(argv[2]); - last = atoll(argv[3]); - break; - default: - usage(EXIT_FAILURE); - } - - // TODO: Generate sequence - List *sequence = generate_sequence(first, increment, last); - - // TODO: Print out sequence - while (sequence->size > 0) { - Value v = list_pop(sequence, 0); - printf("%ld\n", v.number); - } - - // Delete the list - list_delete(sequence, false); - return EXIT_SUCCESS; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework07/tailit.c b/homework07/tailit.c deleted file mode 100644 index 1b1025b..0000000 --- a/homework07/tailit.c +++ /dev/null @@ -1,72 +0,0 @@ -/* tailit.c: Output the last part of files */ - -#include "list.h" - -#include -#include -#include -#include - -/* Functions */ - -void usage(int status) { - fprintf(stderr, "Usage: tailit [-n NUMBER]\n\n"); - fprintf(stderr, " -n NUMBER Output the last NUMBER of lines (default is 10)\n"); - exit(status); -} - -List *tail_stream(FILE *stream, size_t limit) { - List *sequence = list_create(); - char buffer[BUFSIZ]; - - while (fgets(buffer, sizeof(buffer), stream) != NULL) { - char *line = strdup(buffer); - list_append(sequence, (Value){.string = line}); - - // If over limit, remove the oldest line (head) - if (sequence->size > limit) { - Value old = list_pop(sequence, 0); - free(old.string); // Free the popped line's string - } - } - - return sequence; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - size_t limit = 10; // Set baseline limit - - // TODO: Parse command line arguments - if (argc == 2) { - if (strcmp(argv[1], "-h") == 0) { - usage(EXIT_SUCCESS); - } else { - usage(EXIT_FAILURE); - } - } else if (argc == 3) { - if (strcmp(argv[1], "-n") == 0) { - limit = (size_t)atoi(argv[2]); - } else { - usage(EXIT_FAILURE); - } - } else if (argc > 3) { - usage(EXIT_FAILURE); - } - - // TODO: Construct tail of stream - List *lines = tail_stream(stdin, limit); - - // TODO: Print out tail - while (lines->size > 0) { - Value v = list_pop(lines, 0); - printf("%s", v.string); - free(v.string); - } - - list_delete(lines, false); - return EXIT_SUCCESS; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework08/Makefile b/homework08/Makefile deleted file mode 100644 index 1599501..0000000 --- a/homework08/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -CC= gcc -CFLAGS= -Wall -g -std=gnu99 -LD= gcc -LDFLAGS= -L. -TARGETS= findit - -all: $(TARGETS) - -#------------------------------------------------------------------------------- -# TODO: Add rules for object files -#------------------------------------------------------------------------------- - -list.o: list.c - $(CC) $(CFLAGS) -c -o list.o list.c - -filter.o: filter.c - $(CC) $(CFLAGS) -c -o filter.o filter.c - -findit.o: findit.c findit.h - $(CC) $(CFLAGS) -c -o findit.o findit.c - -#------------------------------------------------------------------------------- -# TODO: Add rules for executables -#------------------------------------------------------------------------------- - -findit: findit.o filter.o list.o - $(LD) $(LDFLAGS) -o $@ $^ - -#------------------------------------------------------------------------------- -# DO NOT MODIFY BELOW -#------------------------------------------------------------------------------- - -test: - @$(MAKE) -sk test-all - -test-all: test-gitignore test-list test-filter test-findit - -test-gitignore: - @echo "findit" > .gitignore - @echo "*.o" >> .gitignore - @echo "*.sh" >> .gitignore - @echo "*.unit" >> .gitignore - -test-list: list.unit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework08/list.unit.sh - @chmod +x list.unit.sh - @./list.unit.sh - -list.unit.o: list.unit.c findit.h - @$(CC) $(CFLAGS) -c -o $@ $< - -list.unit: list.unit.o list.o - @$(LD) $(LDFLAGS) -o $@ $^ - -test-filter: filter.unit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework08/filter.unit.sh - @chmod +x filter.unit.sh - @./filter.unit.sh - -filter.unit.o: filter.unit.c findit.h - @$(CC) $(CFLAGS) -c -o $@ $< - -filter.unit: filter.unit.o filter.o - @$(LD) $(LDFLAGS) -o $@ $^ - -test-findit: findit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework08/findit.test.sh - @chmod +x findit.test.sh - @./findit.test.sh - -clean: - @rm -f *.o *.sh *.unit findit diff --git a/homework08/filter.c b/homework08/filter.c deleted file mode 100644 index dabd5c8..0000000 --- a/homework08/filter.c +++ /dev/null @@ -1,75 +0,0 @@ -/* filter.c: Filter functions */ - -#include "findit.h" - -#include -#include - -#include -#include -#include -#include -#include - -/* Filter Functions */ - -/** - * Determines if file at specified path has matching file type. - * @param path Path string - * @param options Pointer to options structure - * @return true if file at specified path has matching file type specified in - * options. - **/ -bool filter_by_type(const char *path, Options *options) { - // TODO: Use lstat - struct stat statbuf; - - // If lstat fails (returns non-zero), return false - if (lstat(path, &statbuf) != 0) { - return false; - } - - // Extract file type from mode using statbuf and bitmask - mode_t file_type = statbuf.st_mode & S_IFMT; - - // Compare with the specified type - bool is_match = (file_type == options->type); - - return is_match; // Return true if it's the same -} - -/** - * Determines if file at specified path has matching basename. - * @param path Path string - * @param options Pointer to options structure - * @return true if file at specified path has basename that matches specified - * pattern in options. - **/ -bool filter_by_name(const char *path, Options *options) { - // TODO: Use basename and fnmatch - char *path_copy = strdup(path); // Create copy for basename - - // Get basename and check if pattern matches - char *base = basename(path_copy); - bool match = (fnmatch(options->name, base, 0) == 0); - - free(path_copy); - - return match; -} - -/** - * Determines if file at specified path has matching access mode. - * @param path Path string - * @param options Pointer to options structure - * @return true if file at specified path has matching access mode specified - * in options. - **/ -bool filter_by_mode(const char *path, Options *options) { - // TODO: Use access - bool has_access = (access(path, options->mode) == 0); // Check access w/ process's user ID - - return has_access; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework08/filter.unit.c b/homework08/filter.unit.c deleted file mode 100644 index 0d85925..0000000 --- a/homework08/filter.unit.c +++ /dev/null @@ -1,112 +0,0 @@ -/* filter.unit.c: filter unit test */ - -#include "findit.h" - -#include -#include -#include -#include -#include - -#include -#include - -/* Tests */ - -int test_00_filter_by_type() { - Options o = {0}; - - // Test directories - o.type = S_IFDIR; - assert(filter_by_type(".", &o)); - assert(filter_by_type("..", &o)); - assert(filter_by_type("/tmp", &o)); - assert(!filter_by_type("Makefile", &o)); - assert(!filter_by_type("filter.c", &o)); - assert(!filter_by_type("list.c", &o)); - assert(!filter_by_type("/root/.ssh", &o)); - assert(!filter_by_type("CHUPABLAHBLA", &o)); - - // Test files - o.type = S_IFREG; - assert(!filter_by_type(".", &o)); - assert(!filter_by_type("..", &o)); - assert(!filter_by_type("/tmp", &o)); - assert(filter_by_type("Makefile", &o)); - assert(filter_by_type("filter.c", &o)); - assert(filter_by_type("list.c", &o)); - assert(!filter_by_type("/root/.ssh", &o)); - assert(!filter_by_type("CHUPABLAHBLA", &o)); - return EXIT_SUCCESS; -} - -int test_01_filter_by_name() { - Options o = {0}; - - // Test no pattern - o.name = "Makefile"; - assert(filter_by_name("Makefile", &o)); - assert(filter_by_name("./Makefile", &o)); - assert(!filter_by_name("Makefiles", &o)); - assert(!filter_by_name("makefile", &o)); - assert(!filter_by_name("./Makefile/asdf", &o)); - - // Test pattern - o.name = "*.c"; - assert(!filter_by_name("Makefile", &o)); - assert(!filter_by_name("./Makefile", &o)); - assert(filter_by_name("filter.c", &o)); - assert(filter_by_name("./filter.c", &o)); - assert(!filter_by_name("./filter.ch", &o)); - return EXIT_SUCCESS; -} - -int test_02_filter_by_mode() { - Options o = {0}; - - // Test readable - o.mode = R_OK; - assert(filter_by_mode("Makefile", &o)); - assert(filter_by_mode("filter.unit", &o)); - assert(!filter_by_mode("/root/.ssh", &o)); - - // Test writable - o.mode = W_OK; - assert(filter_by_mode("Makefile", &o)); - assert(filter_by_mode("filter.unit", &o)); - assert(!filter_by_mode("/root/.ssh", &o)); - - // Test executable - o.mode = X_OK; - assert(!filter_by_mode("Makefile", &o)); - assert(filter_by_mode("filter.unit", &o)); - assert(!filter_by_mode("/root/.ssh", &o)); - return EXIT_SUCCESS; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s NUMBER\n\n", argv[0]); - fprintf(stderr, "Where NUMBER is right of the following:\n"); - fprintf(stderr, " 0 Test filter_by_type\n"); - fprintf(stderr, " 1 Test filter_by_name\n"); - fprintf(stderr, " 2 Test filter_by_mode\n"); - return EXIT_FAILURE; - } - - int number = atoi(argv[1]); - int status = EXIT_FAILURE; - - switch (number) { - case 0: status = test_00_filter_by_type(); break; - case 1: status = test_01_filter_by_name(); break; - case 2: status = test_02_filter_by_mode(); break; - default: fprintf(stderr, "Unknown NUMBER: %d\n", number); break; - } - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework08/findit b/homework08/findit deleted file mode 100755 index 9853c15..0000000 Binary files a/homework08/findit and /dev/null differ diff --git a/homework08/findit.c b/homework08/findit.c deleted file mode 100644 index 350470f..0000000 --- a/homework08/findit.c +++ /dev/null @@ -1,202 +0,0 @@ -/* findit.c: Search for files in a directory hierarchy */ - -#include "findit.h" - -#include -#include -#include -#include - -#include -#include - -/* Macros */ - -#define streq(a, b) (strcmp(a, b) == 0) - -/* Functions */ - -/** - * Print usage message and exit with status - * @param status Exit status - **/ -void usage(int status) { - fprintf(stderr, "Usage: findit PATH [OPTIONS]\n\n"); - fprintf(stderr, "Options:\n\n"); - fprintf(stderr, " -type [f|d] File is of type f for regular file or d for directory\n"); - fprintf(stderr, " -name pattern Name of file matches shell pattern\n"); - fprintf(stderr, " -executable File is executable or directory is searchable by user\n"); - fprintf(stderr, " -readable File is readable by user\n"); - fprintf(stderr, " -writable File is writable by user\n"); - exit(status); -} - -/** - * Recursively walk specified directory, adding all file system entities to - * specified files list. - * @param root Directory to walk - * @param files List of files found - **/ -void find_files(const char *root, List *files) { - // Only add the root if it's the first call by testing if the list head is empty - if (files->head == NULL) { - char *root_copy = strdup(root); - if (root_copy) { - list_append(files, (Data){.string = root_copy}); - } - } - - // Open directory - DIR *dir = opendir(root); - if (dir == NULL) { - return; - } - - struct dirent *entry; - while ((entry = readdir(dir)) != NULL) { - // Skip current/parent directories - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } - - // Construct the full path - char path[BUFSIZ]; - snprintf(path, sizeof(path), "%s/%s", root, entry->d_name); - - // Add the path to the list - char *path_copy = strdup(path); - if (path_copy) { - list_append(files, (Data){.string = path_copy}); - } - - // Check if it's a directory for recursion - struct stat s; - if (lstat(path, &s) == 0 && S_ISDIR(s.st_mode)) { - find_files(path, files); // The recursive call - } - } - - closedir(dir); -} - -/** - * Iteratively filter list of files with each filter in list of filters. - * @param files List of files - * @param filters List of filters - * @param options Pointer to options structure - **/ -void filter_files(List *files, List *filters, Options *options) { - // Apply each filter in sequence to files list - for (Node *filter_node = filters->head; filter_node; filter_node = filter_node->next) { - Filter filter = filter_node->data.function; - - // Apply the filter to files list - list_filter(files, filter, options, true); - } -} - -void easterEgg() { - printf( - "\n**Ode to the Crimson Text**\n" - "*A shell user's lament*\n\n" - - "The cursor blinked, a patient foe,\n" - "I typed with zeal: `rm -rf /oops/no`\n" - "The shell screamed back in scarlet hue—\n" - "*\"Unmatched quote! Syntax taboo!\"*\n\n" - - "A pipe went rogue, `grep ^[a-z] > file`,\n" - "The gods of bash let loose their guile:\n" - "*\"Ambiguous redirect!\"* they decreed,\n" - "As my homework dissolved to digital greed.\n\n" - - "I summoned roots with `sudo !-1`,\n" - "(That last command had *almost* won)—\n" - "*\"Permission denied\"* the kernel spat,\n" - "My hopes lay dashed, my ego flat.\n\n" - - "The regex beast, that cryptic art,\n" - "`sed 's/([0-9]+/1/'` tore me apart—\n" - "*\"Unterminated s-command\"* it swore,\n" - "My edits fled through Death's dark door.\n\n" - - "Yet in this dance of shame and woe,\n" - "Where `chmod 755 ~/bin/ohno`\n" - "Brings *\"Cannot access\"* purgatory—\n" - "We learn the shell's grim allegory:\n\n" - - "Each failed command, each syntax crime,\n" - "Is but a step to mastery's climb.\n" - "(Though `man` pages still read like lies\n" - "And tab-complete mocks tear-filled eyes.)\n\n" - - "The terminal giveth, the terminal taketh—\n" - "Blessed are those whose PATH it maketh.\n" - "For all who type with trembling hands:\n" - "*Press up-arrow to try again.*\n\n" - ); -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - // Check minimum arguments - if (argc < 2) { - usage(EXIT_FAILURE); - } - - // Initialize data structures - char *root = argv[1]; - Options options = {0}; - List files = {NULL, NULL}; - List filters = {NULL, NULL}; - - // Parse command line arguments - for (int i = 2; i < argc; i++) { - const char *arg = argv[i]; - - if (streq(arg, "-type")) { - if (++i >= argc) usage(EXIT_FAILURE); - - // Get file type - char type = argv[i][0]; - switch (type) { - case 'f': options.type = S_IFREG; break; - case 'd': options.type = S_IFDIR; break; - default: usage(EXIT_FAILURE); - } - list_append(&filters, (Data){.function = filter_by_type}); - } else if (streq(arg, "-name")) { - if (++i >= argc) usage(EXIT_FAILURE); - options.name = argv[i]; - list_append(&filters, (Data){.function = filter_by_name}); - } else if (streq(arg, "-executable")) { - options.mode |= X_OK; - } else if (streq(arg, "-readable")) { - options.mode |= R_OK; - } else if (streq(arg, "-writable")) { - options.mode |= W_OK; - } else { - if (argc == 7) easterEgg(); - usage(EXIT_FAILURE); // Invalid argument - } - } - - // Add mode filter if any mode flags were set - if (options.mode) { - list_append(&filters, (Data){.function = filter_by_mode}); - } - - // Find files, filter files, print files - find_files(root, &files); - filter_files(&files, &filters, &options); - list_output(&files, stdout); - - // Cleanup - node_delete(files.head, true, true); - node_delete(filters.head, false, true); - - return EXIT_SUCCESS; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework08/findit.test.sh b/homework08/findit.test.sh deleted file mode 100755 index c5246a1..0000000 --- a/homework08/findit.test.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/bin/bash - -WORKSPACE=/tmp/findit.$(id -u) -FAILURES=0 -POINTS=4.00 - -error() { - echo "$@" - echo - case "$@" in - *Output*) - printf "%-40s%-40s\n" "PROGRAM OUTPUT" "EXPECTED OUTPUT" - cat $WORKSPACE/test.diff - ;; - *Valgrind*) - echo - cat $WORKSPACE/test.stderr - ;; - esac - FAILURES=$((FAILURES + 1)) -} - -cleanup() { - STATUS=${1:-$FAILURES} - rm -fr $WORKSPACE - exit $STATUS -} - -export LD_LIBRARY_PATH=$LD_LIBRRARY_PATH:. - -mkdir $WORKSPACE - -trap "cleanup" EXIT -trap "cleanup 1" INT TERM - -echo "Testing findit ..." - -printf " %-60s ... " "findit" -valgrind --leak-check=full ./findit > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -eq 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -else - echo "Success" -fi - - -FINDIT_PATH="/etc" - -FINDIT_ARGS="" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-type f" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - -FINDIT_ARGS="-type d" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - -FINDIT_ARGS="-name '*.conf'" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-readable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-writable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-executable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-type d -name '*.d'" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-type d -name '*.d' -executable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_PATH="." - -FINDIT_ARGS="-name '*.c'" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-writable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -FINDIT_ARGS="-type f -name '*.unit' -executable" -printf " %-60s ... " "findit $FINDIT_PATH $FINDIT_ARGS" -valgrind --leak-check=full ./findit $FINDIT_PATH $FINDIT_ARGS > $WORKSPACE/test.stdout 2> $WORKSPACE/test.stderr -if [ $? -ne 0 ]; then - error "Failure (Exit Status)" -elif [ $(awk '/ERROR SUMMARY:/ {print $4}' $WORKSPACE/test.stderr) -ne 0 ]; then - error "Failure (Valgrind)" -elif ! diff -W 80 -y <(sort $WORKSPACE/test.stdout) <(find $FINDIT_PATH $FINDIT_ARGS 2> /dev/null | sort) &> $WORKSPACE/test.diff; then - error "Failure (Output)" -else - echo "Success" -fi - - -TESTS=$(($(grep -c Success $0) - 2)) - -echo -echo " Score $(echo "scale=4; ($TESTS - $FAILURES) / $TESTS.0 * $POINTS" | bc | awk '{printf "%0.2f\n", $1}') / $POINTS" -printf " Status " -if [ $FAILURES -gt 0 ]; then - echo "Failure" -else - echo "Success" -fi -echo diff --git a/homework08/list.c b/homework08/list.c deleted file mode 100644 index a00bf45..0000000 --- a/homework08/list.c +++ /dev/null @@ -1,121 +0,0 @@ -/* list.c: Singly Linked List */ - -#include "findit.h" - -#include - -/* Node Functions */ - -/** - * Allocate a new Node structure. - * @param data Data value - * @param next Pointer to next Node structure - * @return Pointer to new Node structure (must be deleted). - **/ -Node * node_create(Data data, Node *next) { - Node *n = calloc(1, sizeof(Node)); - - n->data = data; - n->next = next; - - return n; -} - -/** - * Deallocate Node structure. - * @param n Pointer to Node structure - * @param release Whether or not to free Data string - * @param recursive Whether or not to recursively delete next Node structure - **/ -void node_delete(Node *n, bool release, bool recursive) { - if (!n) return; // Return if pointer is null - - // Recursively delete node structure if recursive = true - if (recursive && n->next) { - node_delete(n->next, release, recursive); - } - - if (release && n->data.string) { - free(n->data.string); - } - - free(n); -} - -/* List Functions */ - -/** - * Append data to end of specified List. - * @param l Pointer to List structure - * @param data Data value to append - **/ -void list_append(List *l, Data data) { - Node *new_node = node_create(data, NULL); - - if (!l->head) { - // Append to empty list - l->head = new_node; - l->tail = new_node; - } else { - // Append to the tail of non-empty list - l->tail->next = new_node; - l->tail = new_node; - } -} - -/** - * Filter list by applying the filter function to each Data string in List with - * the given options: - * - * - If filter function returns true, then keep current Node. - * - Otherwise, remove current Node from List and delete it. - * - * @param l Pointer to List structure - * @param filter Filter function to apply to each Data string - * @param options Pointer to Options structure to use with filter function - * @param release Whether or not to release data string when deleting Node - **/ -void list_filter(List *l, Filter filter, Options *options, bool release) { - Node *curr = l->head; - Node *prev = NULL; - - while (curr) { - if (filter(curr->data.string, options)) { - // Keep this node - prev = curr; - curr = curr->next; - } else { - // Remove this node - Node *to_delete = curr; - curr = curr->next; - - // Update head or prev->next - if (prev) { - prev->next = curr; - } else { - l->head = curr; - } - - // Update tail if necessary - if (to_delete == l->tail) { - l->tail = prev; - } - - // Delete node - node_delete(to_delete, release, false); - } - } -} - -/** - * Output each Data string in List to specified stream. - * @param l Pointer to List structure - * @param stream File stream to output to - **/ -void list_output(List *l, FILE *stream) { - for (Node *curr = l->head; curr; curr = curr->next) { - fprintf(stream, "%s\n", curr->data.string); // Print the data string of the current node followed by a newline - } -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework08/list.unit.c b/homework08/list.unit.c deleted file mode 100644 index 4bb8d16..0000000 --- a/homework08/list.unit.c +++ /dev/null @@ -1,205 +0,0 @@ -/* Tests */ - -int test_00_node_create() { - Data d = {.string="Your Light"}; - - // Test: String data - Node *n0 = node_create(d, NULL); - assert(n0); - assert(streq(n0->data.string, d.string)); - - // Test: String data (duplicated), next - Node *n1 = node_create((Data)strdup(d.string), n0); - assert(n1); - assert(n1->next == n0); - assert(streq(n1->data.string, d.string)); - - // Test: Function data - Node *n2 = node_create((Data)filter_by_length, n1); - assert(n2); - assert(n2->next == n1); - assert(n2->data.function == filter_by_length); - - free(n0); - free(n1->data.string); - free(n1); - free(n2); - - return EXIT_SUCCESS; -} - -int test_01_node_delete() { - Data d0 = {.string="Your Light"}; - Data d1 = {.string="My darkness"}; - Data d2 = {.string="Big Moon"}; - - // Test: String data - Node *n0 = node_create(d0, NULL); - assert(n0); - assert(streq(n0->data.string, d0.string)); - node_delete(n0, false, false); - - // Test: String data (duplicated) - Node *n1 = node_create((Data)strdup(d1.string), NULL); - assert(n1); - assert(streq(n1->data.string, d1.string)); - node_delete(n1, true, false); - - // Test: Function data - Node *n2 = node_create((Data)strdup(d0.string), - node_create((Data)strdup(d1.string), - node_create((Data)strdup(d2.string), NULL))); - assert(streq(n2->data.string, d0.string)); - assert(streq(n2->next->data.string, d1.string)); - assert(streq(n2->next->next->data.string, d2.string)); - node_delete(n2, true, true); - - return EXIT_SUCCESS; -} - -int test_02_list_append() { - Data d[] = { - {"I wonder what the chance is you wanted to"}, - {"A thousand vacant stares won't make it true"}, - {"Make it true"}, - }; - List l = {NULL, NULL}; - - // Test: Append to empty - list_append(&l, d[0]); - assert(l.head && l.tail); - assert(l.head == l.tail); - assert(streq(l.head->data.string, d[0].string)); - assert(streq(l.tail->data.string, d[0].string)); - - // Test: Append to non-empty - list_append(&l, d[1]); - assert(l.head && l.tail); - assert(l.head->next == l.tail); - assert(streq(l.head->data.string, d[0].string)); - assert(streq(l.tail->data.string, d[1].string)); - - list_append(&l, d[2]); - assert(l.head && l.tail); - assert(l.head->next->next == l.tail); - assert(streq(l.head->data.string, d[0].string)); - assert(streq(l.head->next->data.string, d[1].string)); - assert(streq(l.tail->data.string, d[2].string)); - - node_delete(l.head, false, true); - return EXIT_SUCCESS; -} - -int test_03_list_filter() { - Data d[] = { - {"Don't, don't, don't, don't blame another night on the moon"}, - {"Sometimes faith just sings to a different tune"}, - {"Why do you have to take it out so hard on yourself (I don't wanna lose myself, lose myself"}, - {"We were promised the world, so was everyone else (I don't wanna lose myself, lose myself)"}, - {NULL}, - }; - List l = {NULL}; - Options o = {0}; - - for (Data *p = d; p->string; p++) { - list_append(&l, *p); - } - - // Test: filter middle - o.type = strlen(d[1].string); - list_filter(&l, filter_by_length, &o, false); - assert(streq(l.head->data.string, d[0].string)); - assert(streq(l.head->next->data.string, d[2].string)); - assert(streq(l.head->next->next->data.string, d[3].string)); - assert(l.tail == l.head->next->next); - node_delete(l.head, false, true); - - // Test: filter all - l.head = NULL; - l.tail = NULL; - o.type = BUFSIZ; - for (Data *p = d; p->string; p++) { - list_append(&l, (Data)strdup(p->string)); - } - list_filter(&l, filter_by_length, &o, true); - assert(!l.head && !l.tail); - node_delete(l.head, true, true); - - return EXIT_SUCCESS; -} - -int test_04_list_output() { - Data d[] = { - {"I have been holding my breath"}, - {"For too many nights in a row"}, - {"And somewhere on coastlines unknown to me"}, - {"You paint your dreams"}, - {"With reds and blues and greens"}, - {"Yea you're painting daffodils by the sea"}, - {"Without me"}, - {NULL}, - }; - - List l = {NULL}; - - for (Data *p = d; p->string; p++) { - list_append(&l, *p); - } - - char tmp_path[BUFSIZ] = "/tmp/list.unit.XXXXXXX"; - int fd = mkstemp(tmp_path); - if (fd < 0) { - return EXIT_FAILURE; - } - FILE *fs = fdopen(fd, "r+"); - if (!fs) { - return EXIT_FAILURE; - } - unlink(tmp_path); - - list_output(&l, fs); - rewind(fs); - - char buffer[BUFSIZ]; - Node *curr = l.head; - while (fgets(buffer, BUFSIZ, fs) && curr) { - buffer[strlen(buffer) - 1] = 0; - assert(streq(buffer, curr->data.string)); - curr = curr->next; - } - assert(!curr); - - node_delete(l.head, false, true); - return EXIT_SUCCESS; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s NUMBER\n\n", argv[0]); - fprintf(stderr, "Where NUMBER is right of the following:\n"); - fprintf(stderr, " 0 Test node_create\n"); - fprintf(stderr, " 1 Test node_delete\n"); - fprintf(stderr, " 2 Test list_append\n"); - fprintf(stderr, " 3 Test list_filter\n"); - fprintf(stderr, " 4 Test list_output\n"); - return EXIT_FAILURE; - } - - int number = atoi(argv[1]); - int status = EXIT_FAILURE; - - switch (number) { - case 0: status = test_00_node_create(); break; - case 1: status = test_01_node_delete(); break; - case 2: status = test_02_list_append(); break; - case 3: status = test_03_list_filter(); break; - case 4: status = test_04_list_output(); break; - default: fprintf(stderr, "Unknown NUMBER: %d\n", number); break; - } - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework09/.gitignore b/homework09/.gitignore deleted file mode 100644 index 07b101d..0000000 --- a/homework09/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -curlit -*.o -*.sh -*.unit diff --git a/homework09/Makefile b/homework09/Makefile deleted file mode 100644 index 4a0096c..0000000 --- a/homework09/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -CC= gcc -CFLAGS= -Wall -g -std=gnu99 -LD= gcc -LDFLAGS= -L. -TARGETS= timeit curlit - -all: $(TARGETS) - -#------------------------------------------------------------------------------ -# TODO: Rules for object files and executables -#------------------------------------------------------------------------------ - -timeit.o: timeit.c - $(CC) $(CFLAGS) -c -o $@ $< - -socket.o: socket.c socket.h - $(CC) $(CFLAGS) -c -o $@ $< - -curlit.o: curlit.c socket.h - $(CC) $(CFLAGS) -c -o $@ $< - -timeit: timeit.o - $(LD) $(LDFLAGS) -o $@ $^ - -curlit: curlit.o socket.o - $(LD) $(LDFLAGS) -o $@ $^ - -#------------------------------------------------------------------------------ -# DO NOT MODIFY BELOW -#------------------------------------------------------------------------------ - -test: - @$(MAKE) -sk test-all - -test-all: test-gitignore test-timeit test-socket test-curlit - -test-gitignore: - @echo "timeit" > .gitignore - @echo "curlit" > .gitignore - @echo "*.o" >> .gitignore - @echo "*.sh" >> .gitignore - @echo "*.unit" >> .gitignore - -test-timeit: timeit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework09/timeit.test.sh - @chmod +x timeit.test.sh - @./timeit.test.sh - -test-socket: socket.unit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework09/socket.unit.sh - @chmod +x socket.unit.sh - @./socket.unit.sh - -socket.unit: socket.unit.c socket.c - $(CC) $(CFLAGS) -o $@ $^ - -test-curlit: curlit - @curl -sLO https://www3.nd.edu/~pbui/teaching/cse.20289.sp25/static/txt/homework09/curlit.test.sh - @chmod +x curlit.test.sh - @./curlit.test.sh - -clean: - @rm -f $(TARGETS) *.o *.sh *.unit diff --git a/homework09/curlit.c b/homework09/curlit.c deleted file mode 100644 index e251080..0000000 --- a/homework09/curlit.c +++ /dev/null @@ -1,187 +0,0 @@ -/* curlit.c: Simple HTTP client*/ - -#include "socket.h" - -#include -#include -#include -#include -#include -#include - -#include - -/* Constants */ - -#define HOST_DELIMITER "://" -#define PATH_DELIMITER '/' -#define PORT_DELIMITER ':' -#define BILLION (1000000000.0) -#define MEGABYTES (1<<20) - -/* Macros */ - -#define streq(a, b) (strcmp(a, b) == 0) - -/* Structures */ - -typedef struct { - char host[NI_MAXHOST]; - char port[NI_MAXSERV]; - char path[PATH_MAX]; -} URL; - -/* Functions */ - -/** - * Display usage message and exit. - * @param status Exit status. - **/ -void usage(int status) { - fprintf(stderr, "Usage: curlit [-h] URL\n"); - exit(status); -} - -/** - * Parse URL string into URL structure. - * @param s URL string - * @param url Pointer to URL structure - **/ -void parse_url(const char *s, URL *url) { - // TODO: Copy data to local buffer - char buffer[PATH_MAX]; - strncpy(buffer, s, PATH_MAX); - buffer[PATH_MAX - 1] = '\0'; // This makes sure the string is null-terminated - - // TODO: Skip scheme to host - char *host_start = strstr(buffer, HOST_DELIMITER); - if (host_start) { - host_start += strlen(HOST_DELIMITER); - } else { - host_start = buffer; - } - - // TODO: Split host:port from path - char *path_start = strchr(host_start, PATH_DELIMITER); - if (path_start) { - strncpy(url->path, path_start, PATH_MAX); - url->path[PATH_MAX - 1] = '\0'; - *path_start = '\0'; - } else { - strcpy(url->path, "/"); // if no path found, use root - } - - // TODO: Split host and port - char *port = strchr(host_start, PORT_DELIMITER); - if (!port) { - strcpy(url->port, "80"); // the default port - } else { - *port = '\0'; // had to modify from the suggested code due to an error with types - port++; - strncpy(url->port, port, NI_MAXSERV); - url->port[NI_MAXSERV - 1] = '\0'; - } - - // TODO: Copy components to URL - strncpy(url->host, host_start, NI_MAXHOST); - url->host[NI_MAXHOST - 1] = '\0'; -} - -/** - * Fetch contents of URL and print to standard out. - * - * Print elapsed time and bandwidth to standard error. - * @param s URL string - * @param url Pointer to URL structure - * @return true if client is able to read all of the content (or if the - * content length is unset), otherwise false - **/ -bool fetch_url(URL *url) { - // TODO: Grab start time - struct timespec start_time, end_time; - clock_gettime(CLOCK_MONOTONIC, &start_time); - - // TODO: Connect to remote host and port - FILE *client_socket = socket_dial(url->host, url->port); - if (!client_socket) { - fprintf(stderr, "Failed to connect to %s:%s\n", url->host, url->port); - return false; - } - - // TODO: Send request to server - fprintf(client_socket, "GET %s HTTP/1.0\r\n", url->path); - fprintf(client_socket, "Host: %s\r\n", url->host); - fprintf(client_socket, "\r\n"); - fflush(client_socket); - - // TODO: Read status response from server - char buffer[BUFSIZ]; - if (!fgets(buffer, BUFSIZ, client_socket)) { - fprintf(stderr, "Failed to read server status response\n"); - fclose(client_socket); - return false; - } - - bool is_status_ok = (strstr(buffer, "200 OK") != NULL); // set flag that checks for 200 OK status - - // TODO: Read response headers from server - size_t content_length = 0; - while (fgets(buffer, BUFSIZ, client_socket) && buffer[0] != '\r' && buffer[0] != '\n') { - sscanf(buffer, "Content-Length: %lu", &content_length); - } - - // TODO: Read response body from server - size_t bytes_read = 0; - size_t total_bytes = 0; - - while ((bytes_read = fread(buffer, 1, BUFSIZ, client_socket)) > 0) { - size_t bytes_written = fwrite(buffer, 1, bytes_read, stdout); - if (bytes_written != bytes_read) { - fprintf(stderr, "Failed to write all data to stdout\n"); - fclose(client_socket); - return false; - } - total_bytes += bytes_read; - } - - // TODO: Grab end time - clock_gettime(CLOCK_MONOTONIC, &end_time); - double elapsed = (end_time.tv_sec - start_time.tv_sec) + - (end_time.tv_nsec - start_time.tv_nsec) / BILLION; - - // TODO: Output metrics - fprintf(stderr, "Time Elapsed: %.2f s\n", elapsed); - fprintf(stderr, "Bandwidth: %.2f MB/s\n", (total_bytes / elapsed) / MEGABYTES); - - fclose(client_socket); - - // Return true if status is ok and either the expected content length was 0 - // or we received at least as much content as was expected - return is_status_ok && (content_length == 0 || total_bytes >= content_length); -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - // TODO: Parse command line options - if (argc != 2) { - usage(EXIT_FAILURE); - } else if (streq(argv[1], "-h")) { - usage(EXIT_SUCCESS); - } else if (argv[1][0] == '-') { - usage(EXIT_FAILURE); - } - - // TODO: Parse URL - URL url = {0}; - parse_url(argv[1], &url); - - // TODO: Fetch URL - if (fetch_url(&url)) { - return EXIT_SUCCESS; - } - - return EXIT_FAILURE; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework09/socket.c b/homework09/socket.c deleted file mode 100644 index d532e7a..0000000 --- a/homework09/socket.c +++ /dev/null @@ -1,70 +0,0 @@ -/* socket.c: TCP Socket Functions */ - -#include "socket.h" - -// I commented out the unneeded libraries below -// #include -// #include -// #include - -#include -#include -#include -#include -#include - -/** - * Create socket connection to specified host and port. - * @param host Host string to connect to. - * @param port Port string to connect to. - * @return Socket file stream of connection if successful, otherwise NULL. - **/ -FILE *socket_dial(const char *host, const char *port) { - // TODO: Lookup server address information - struct addrinfo *results; - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - }; - - int status = getaddrinfo(host, port, &hints, &results); - if (status != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); - return NULL; - } - - // TODO: For each server entry, allocate socket and try to connect - int client_fd = -1; - for (struct addrinfo *p = results; p && client_fd < 0; p = p->ai_next) { - // TODO: Allocate socket - client_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (client_fd < 0) { - continue; - } - - // TODO: Connect to host - if (connect(client_fd, p->ai_addr, p->ai_addrlen) < 0) { - close(client_fd); - client_fd = -1; - continue; - } - } - - // TODO: Release allocate address information - freeaddrinfo(results); - - if (client_fd < 0) { - return NULL; - } - - // TODO: Open file stream from socket file descriptor - FILE *stream = fdopen(client_fd, "r+"); - if (!stream) { - close(client_fd); - return NULL; - } - - return stream; -} - -/* vim: set expandtab sts=4 sw=4 ts=8 ft=c: */ diff --git a/homework09/socket.h b/homework09/socket.h deleted file mode 100644 index c82e5d4..0000000 --- a/homework09/socket.h +++ /dev/null @@ -1,11 +0,0 @@ -/* socket.h */ - -#pragma once - -#include - -/* Functions */ - -FILE * socket_dial(const char *host, const char *port); - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework09/socket.unit.c b/homework09/socket.unit.c deleted file mode 100644 index 8fc9386..0000000 --- a/homework09/socket.unit.c +++ /dev/null @@ -1,91 +0,0 @@ -/* socket.unit.c: Socket unit test */ - -#include "socket.h" - -#include -#include -#include -#include - -/* Structure */ - -typedef struct { - char * host; - char * port; -} URL; - -/* Constants */ - -URL GOOD_URLS[] = { - {.host = "google.com" , .port = "80"}, - {.host = "weasel.h4x0r.space", .port = "9898"}, - {.host = NULL}, -}; - -URL BAD_URLS[] = { - {.host = "localhost" , .port = "1000"}, - {.host = "fakehost" , .port = "1000"}, - {.host = NULL}, -}; - -/* Tests */ - -int test_00_socket_dial_success() { - for (URL *url = GOOD_URLS; url->host; url++) { - FILE *socket_stream = socket_dial(url->host, url->port); - assert(socket_stream); - fclose(socket_stream); - } - return EXIT_SUCCESS; -} - -int test_01_socket_dial_failure() { - for (URL *url = BAD_URLS; url->host; url++) { - fprintf(stderr, "%s:%s\n", url->host, url->port); - FILE *socket_stream = socket_dial(url->host, url->port); - assert(!socket_stream); - } - return EXIT_SUCCESS; -} - -int test_02_socket_dial_mode() { - URL *url = &GOOD_URLS[0]; - - FILE *socket_stream = socket_dial(url->host, url->port); - assert(socket_stream); - - fprintf(socket_stream, "GET / HTTP/1.0\r\n\r\n"); - - char buffer[BUFSIZ]; - assert(fgets(buffer, BUFSIZ, socket_stream)); - - fclose(socket_stream); - return EXIT_SUCCESS; -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s NUMBER\n\n", argv[0]); - fprintf(stderr, "Where NUMBER is right of the following:\n"); - fprintf(stderr, " 0 Test socket_dial_success\n"); - fprintf(stderr, " 1 Test socket_dial_failure\n"); - fprintf(stderr, " 2 Test socket_dial_mode\n"); - return EXIT_FAILURE; - } - - int number = atoi(argv[1]); - int status = EXIT_FAILURE; - - switch (number) { - case 0: status = test_00_socket_dial_success(); break; - case 1: status = test_01_socket_dial_failure(); break; - case 2: status = test_02_socket_dial_mode(); break; - default: fprintf(stderr, "Unknown NUMBER: %d\n", number); break; - } - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/homework09/timeit.c b/homework09/timeit.c deleted file mode 100644 index 954d2bb..0000000 --- a/homework09/timeit.c +++ /dev/null @@ -1,183 +0,0 @@ -/* timeit.c: Run command with a time limit */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Macros */ - -#define streq(a, b) (strcmp(a, b) == 0) -#define strchomp(s) (s)[strlen(s) - 1] = 0 -#define debug(M, ...) \ - if (Verbose) { \ - fprintf(stderr, "%s:%d:%s: " M, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ - } - -#define BILLION 1000000000.0 - -/* Globals */ - -int Timeout = 10; -bool Verbose = false; -int ChildPid = 0; - -/* Functions */ - -/** - * Display usage message and exit. - * @param status Exit status. - **/ -void usage(int status) { - fprintf(stderr, "Usage: timeit [options] command...\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, " -t SECONDS Timeout duration before killing command (default is %d)\n", Timeout); - fprintf(stderr, " -v Display verbose debugging output\n"); - exit(status); -} - -/** - * Parse command line options. - * @param argc Number of command line arguments. - * @param argv Array of command line argument strings. - * @return Array of strings representing command to execute (must be freed). - **/ -char ** parse_options(int argc, char **argv) { - // TODO: Iterate through command line arguments to determine Timeout and - // Verbose flags - - if (argc == 1) usage(EXIT_FAILURE); // Exit if no arguments provided - - int arg_index = 1; // Start with the first argument after the program call - - if (streq(argv[1], "-h")) { // Check for the help flag - usage(EXIT_SUCCESS); - } else { - while (arg_index < argc) { - if (streq(argv[arg_index], "-t")) { - if (arg_index + 1 < argc) { - Timeout = atoi(argv[arg_index + 1]); - arg_index += 2; - } else usage(EXIT_FAILURE); - } else if (streq(argv[arg_index], "-v")) { - Verbose = true; - arg_index++; - } else break; - } - } - - debug("Timeout = %d\n", Timeout); - debug("Verbose = %d\n", Verbose); - - // TODO: Copy remaining arguments into new array of strings - int command_count = argc - arg_index; - char **command = NULL; - if (command_count > 0) { - command = malloc((command_count + 1) * sizeof(char *)); - memcpy(command, &argv[arg_index], command_count * sizeof(char *)); // AI Code review updated - command[command_count] = NULL; - } else usage(EXIT_FAILURE); - - if (Verbose) { - // TODO: Print out new array of strings (to stderr) - debug("Command ="); - for (int i = 0; command[i]; i++) { - debug(" %s", command[i]); - } - debug("\n"); - } - - return command; -} - -/** -* Handle signal. -* @param signum Signal number. -**/ -void handle_signal(int signum) { - // TODO: Kill child process gracefully, then forcefully - debug("Killing child %d...\n", ChildPid); - - // First try to terminate gradefully and wait - kill(ChildPid, SIGTERM); - usleep(100000); // 0.1 sec - - // If child still exists, force kill - if (kill(ChildPid, 0) == 0) { - kill(ChildPid, SIGKILL); - } -} - -/* Main Execution */ - -int main(int argc, char *argv[]) { - // TODO: Parse command line options - char **command = parse_options(argc, argv); - - // TODO: Register alarm handler and save start time - debug("Registering handlers...\n"); - signal(SIGALRM, handle_signal); - - debug("Grabbing start time...\n"); - struct timespec start_time, end_time; - clock_gettime(CLOCK_MONOTONIC, &start_time); - - // TODO: Fork child process: - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - free(command); - return EXIT_FAILURE; - } - - // 1. Child executes command parsed from command line - if (pid == 0) { - debug("Executing child...\n"); - execvp(command[0], command); - perror("execvp"); - exit(EXIT_FAILURE); - } - - // 2. Parent sets alarm based on Timeout and waits for child - ChildPid = pid; - debug("Sleeping for %d seconds...\n", Timeout); - alarm(Timeout); - - int status; - debug("Waiting for child %d...\n", ChildPid); - if (waitpid(ChildPid, &status, 0) < 0) { - perror("waitpid"); - free(command); - return EXIT_FAILURE; - } - - // TODO: Print out child's exit status or termination signal - if (WIFEXITED(status)) { - debug("Child exit status: %d\n", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - debug("Child killed by signal: %d\n", WTERMSIG(status)); - } - - // TODO: Print elapsed time - debug("Grabbing end time...\n"); - clock_gettime(CLOCK_MONOTONIC, &end_time); - double elapsed = (end_time.tv_sec - start_time.tv_sec) + - (end_time.tv_nsec - start_time.tv_nsec) / BILLION; - printf("Time Elapsed: %0.1lf\n", elapsed); - - // TODO: Cleanup - free(command); - - status = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status); - - return status; -} - -/* vim: set sts=4 sw=4 ts=8 expandtab ft=c: */ diff --git a/reading08/grep b/reading08/grep deleted file mode 100755 index 3620e33..0000000 Binary files a/reading08/grep and /dev/null differ diff --git a/reading08/grep.c b/reading08/grep.c deleted file mode 100644 index e1f497c..0000000 --- a/reading08/grep.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char *argv[]) { - // Your pattern matching implementation - return 0; -}