diff --git a/w3-hw/stringfun.c b/w3-hw/stringfun.c
new file mode 100644
index 0000000000000000000000000000000000000000..51e81c9eceeeb7eece8e3d6ef888d65ba0fba91c
--- /dev/null
+++ b/w3-hw/stringfun.c
@@ -0,0 +1,527 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+
+#define BUFFER_SZ 50
+#define SPACE_CHAR ' '
+
+//prototypes
+void usage(char *);
+void print_buff(char *, int);
+int  setup_buff(char *, char *, int);
+
+//prototypes for functions to handle required functionality
+int  count_words(char *, int, int);
+//add additional prototypes here
+void reverse_string(char *, int);
+void word_print(char *, int);
+int string_replace(char *, int, char *, char *);
+int my_strlen(char *); // Custom strlen function
+
+void usage(char *exename){
+    printf("usage: %s [-h|c|r|w|x] \"string\" [other args]\n", exename);
+    
+   //printf("Options:\n");
+   // printf("  -h : Display help information\n");
+   // printf("  -c : Count words in the string\n");
+   // printf("  -r : Reverse the string\n");
+   // printf("  -w : Print words and their lengths\n");
+   // printf("  -x : Replace a word in the string\n");
+
+}
+
+// Custom implementation of strlen() to calculate string length
+int my_strlen(char *str) {
+    int length = 0;    // Initialize length counter
+    while (*(str + length) != '\0') { // Loop until null terminator is reached
+        length++;    // Increment length for each character
+    }
+    return length;   // Return the calculated length
+}
+
+int setup_buff(char *buff, char *user_str, int len){
+    //TODO: #4:  Implement the setup buff as per the directions
+    int user_str_len = 0;   // Tracks the length of the user string
+    int buff_idx = 0;     // Index for the buffer
+    bool space_pending = false;    // Tracks whether a space is waiting to be added
+    char *p = user_str;  // Pointer to iterate through the user string
+
+    bool started = false;   // Tracks if non-space characters have been encountered
+
+  //  if (my_strlen(user_str) > len) {
+     //   return -1;   // Input string is too large for the buffer
+   // }
+
+  //  if (my_strlen(user_str) == 0) {
+   //     return -2; // Return error for empty input
+  //  }
+    
+
+    // Process each character in the input string
+    while (*p != '\0') {
+        if (*p == SPACE_CHAR || *p == '\t') { // Check for whitespace
+            if (started && !space_pending && buff_idx < len) { // Add a single space only once
+                //if (buff_idx < len) {
+                *(buff + buff_idx++) = SPACE_CHAR;
+                user_str_len++;
+                space_pending = true;   // Set space pending to true
+              //  }
+            }
+        } else { 
+           // break;
+            // Non-whitespace character
+            
+            if (buff_idx <= len) {
+                *(buff + buff_idx++) = *p;  // Copy the character to the buffer
+                user_str_len++;
+                space_pending = false;   // Reset space pending for new word
+                started = true; 
+            } else {
+                break;
+            }
+            
+        }
+        p++; // Move to the next character
+    }
+    // Remove the trailing space if any
+    if (buff_idx > 0 && *(buff + buff_idx - 1) == SPACE_CHAR) {
+        buff_idx--;
+        user_str_len--;
+    }
+
+    // Fill the remaining buffer space with dots
+    while (buff_idx < len) {
+        *(buff + buff_idx++) = '.';
+    }
+
+    return (user_str_len > len) ? -1 : user_str_len; // Return length or error
+
+    //return 0; //for now just so the code compiles. 
+}
+
+void print_buff(char *buff, int len){
+    printf("Buffer:  [");
+    for (int i=0; i<len; i++){
+        putchar(*(buff+i));
+    }
+    printf("]\n");
+}
+
+
+
+int count_words(char *buff, int len, int str_len){
+    //YOU MUST IMPLEMENT
+
+    // Ensure that str_len does not exceed len to avoid buffer overflows
+    if (str_len > len) {
+        printf("Error: String length exceeds buffer length.\n");
+        return -1; // Return error code for invalid input
+    }
+
+    int wc = 0;   // Word count
+    bool word_start = false;  // Tracks if we are at the start of a word
+
+    for (int i = 0; i < str_len; i++) {
+        char current = *(buff + i);   // Get the current character
+
+        //if (current == '.') {
+            // Stop counting at the first dot
+          //  break;
+       // }
+
+        if (!word_start && current != SPACE_CHAR) {
+            wc++; // Increment word count at word start
+            word_start = true; // Mark that we are in a word
+        } else if (current == SPACE_CHAR) {
+            word_start = false; // End the current word
+        }
+    }
+
+    return wc; // Return the total word count
+
+
+   // return 0;
+}
+
+//ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS
+
+// Reverse the string in the buffer in place
+void reverse_string(char *buff, int str_len) {
+    int start = 0;   // Start index
+    int end = str_len - 1;  // End index
+
+    while (start < end) {  // Swap until the indices meet
+        char temp = *(buff + start);   // Temporary storage for start character
+        *(buff + start) = *(buff + end); // Swap start and end characters
+        *(buff + end) = temp;
+
+        start++;  // Move start index forward
+        end--;  // Move end index backward
+    }
+}
+
+
+
+void word_print(char *buff, int str_len) {
+    int word_count = 0;  // Total word count
+    int char_count = 0;  // Length of the current word
+    bool at_start = true; // Tracks if at the start of a new word
+
+    printf("Word Print\n");
+    printf("----------\n");
+
+
+    // Loop through the buffer for the string length
+    for (int i = 0; i < str_len; i++) {
+        char current = *(buff + i); // Get the current character
+
+        if (at_start && current != SPACE_CHAR) {
+            // New word found
+            word_count++;
+            printf("%d. ", word_count); // Print word index
+            at_start = false;  // Mark that we are processing a word
+        }
+
+        if (current == SPACE_CHAR) {
+            // End of a word
+            if (char_count > 0) {
+                printf("(%d)\n", char_count); // Print word length
+                char_count = 0;  // Reset character count for next word
+                at_start = true; // Mark start of a new word
+            }
+        } else {
+            if (*(buff + i) == '.') {
+                // Stop processing at the first dot (truncated word)
+                break;
+            }
+            putchar(current); // Print the current character
+            char_count++;  // Increment the character count
+        }
+    }
+
+    // Handle the last word (if it doesn't end with a space)
+    if (char_count > 0) {
+        printf("(%d)\n", char_count); // Print the length of the last word
+    }
+
+    printf("\nNumber of words returned: %d\n", word_count);
+}
+
+/*
+
+int string_replace(char *buff, int len, char *find, char *replace) {
+    char *match = strstr(buff, find);  // Find the first occurrence of the substring
+    if (!match) {
+        return -2; // Substring not found
+    }
+
+    int find_len = my_strlen(find);       // Length of the substring to find
+    int replace_len = my_strlen(replace); // Length of the replacement string
+    int buff_len = my_strlen(buff);       // Current length of the buffer content
+
+    // Calculate the new length after replacement
+    int new_len = buff_len - find_len + replace_len;
+
+    if (new_len > len) {
+        // Truncate the replacement string to fit within the buffer
+        replace_len -= (new_len - len);
+        new_len = len; // Adjust the final buffer length
+    }
+
+    // Check if truncation has shortened the replacement string to zero
+    if (replace_len <= 0) {
+        return -1; // Error: Replacement string cannot fit in the buffer
+    }
+
+    // Move characters after the match to accommodate the replacement
+    memmove(match + replace_len,            // Destination: shift characters after replacement
+            match + find_len,               // Source: characters after the found substring
+            buff_len - (match - buff) - find_len); // Number of characters to move
+
+    // Copy the (possibly truncated) replacement string into the buffer
+    memcpy(match, replace, replace_len);
+
+    // Fill the remaining buffer with dots
+    for (int i = new_len; i < len; i++) {
+        buff[i] = '.'; // Fill unused space with dots
+    }
+
+    // Ensure null-termination for safety
+    buff[len] = '\0';
+
+    return 0; // Success
+}
+*/
+
+int string_replace(char *buff, int len, char *find, char *replace) {
+    char *match = strstr(buff, find);  // Locate the substring to replace
+    if (!match) {
+        return -2; // Substring not found
+    }
+
+    int find_len = my_strlen(find);       // Length of the substring to find
+    int replace_len = my_strlen(replace); // Length of the replacement string
+    int buff_len = my_strlen(buff);       // Current length of the buffer content
+
+    // Calculate the new length after replacement
+    int new_len = buff_len - find_len + replace_len;
+
+    // Allocate a temporary buffer
+    char *temp_buff = (char *)malloc(len);
+    if (!temp_buff) {
+        return -3; // Memory allocation failed
+    }
+
+    // Copy everything up to the match into the temporary buffer
+    int prefix_len = match - buff;
+    strncpy(temp_buff, buff, prefix_len);
+
+    // Append the (possibly truncated) replacement string to the temporary buffer
+    if (replace_len + prefix_len > len) {
+        replace_len = len - prefix_len; // Truncate the replacement string if necessary
+    }
+    strncpy(temp_buff + prefix_len, replace, replace_len);
+
+    // Append the remainder of the original buffer after the match
+    int suffix_start = prefix_len + find_len;
+    int remaining_space = len - (prefix_len + replace_len);
+    if (remaining_space > 0) {
+        strncpy(temp_buff + prefix_len + replace_len, buff + suffix_start, remaining_space);
+    }
+
+    // Ensure the result is properly padded with dots
+    for (int i = new_len; i < len; i++) {
+        temp_buff[i] = '.';
+    }
+
+    // Copy the result back to the original buffer
+    memcpy(buff, temp_buff, len);
+
+    // Free the temporary buffer
+    free(temp_buff);
+
+    return 0; // Success
+}
+
+
+
+
+
+
+
+
+
+int main(int argc, char *argv[]){
+
+    char *buff; // = malloc(BUFFER_SZ);      // Allocate buffer             //placehoder for the internal buffer
+    
+    
+    //if (!buff) {
+       // printf("Error: Memory allocation failed.\n");
+      //  exit(99);                        // Exit on memory allocation failure
+    //}
+
+
+    char *input_string;     //holds the string provided by the user on cmd line
+    char opt;               //used to capture user option from cmd line
+    int  rc;                //used for return codes
+    int  user_str_len;      //length of user supplied string
+
+    //TODO:  #1. WHY IS THIS SAFE, aka what if arv[1] does not exist?
+    //      PLACE A COMMENT BLOCK HERE EXPLAINING
+
+    /* This check ensures that the program has received the correct number of arguments.
+    - If argc < 2, argv[1] does not exist, so the program safely exits with usage instructions.
+    - The second condition (*argv[1] != '-') ensures that the first argument provided
+    starts with a dash ('-'), as required by the command-line syntax.
+    By combining these checks, 
+    we prevent undefined behavior from accessing argv[1] 
+    when it does not exist.
+    */
+    
+
+
+    if ((argc < 2) || (*argv[1] != '-')){
+        usage(argv[0]);
+       // free(buff);
+        exit(1);
+    }
+
+    opt = (char)*(argv[1]+1);   //get the option flag
+
+    //handle the help flag and then exit normally
+    if (opt == 'h'){
+        usage(argv[0]);
+      //  free(buff);
+        exit(0);
+    }
+
+    //WE NOW WILL HANDLE THE REQUIRED OPERATIONS
+
+    //TODO:  #2 Document the purpose of the if statement below
+    //      PLACE A COMMENT BLOCK HERE EXPLAINING
+
+    /*
+    This check ensures that the user provides the required arguments:
+    - argc < 3 indicates that the user has not supplied both an option (argv[1])
+    and the input string (argv[2]).
+    - If this condition is 'true', the program prints usage instructions
+    and exits with an error code of 1 to indicate invalid usage.
+    This prevents undefined behavior caused by accessing missing arguments.
+    */
+    
+
+
+
+
+    if (argc < 3){
+        usage(argv[0]);
+     //   free(buff);
+        exit(1);
+    }
+
+
+
+    input_string = argv[2]; //capture the user input string
+    //user_str_len = setup_buff(buff, input_string, BUFFER_SZ);
+
+    //TODO:  #3 Allocate space for the buffer using malloc and
+    //          handle error if malloc fails by exiting with a 
+    //          return code of 99
+    // CODE GOES HERE FOR #3
+
+    // Allocate space for the buffer
+    buff = (char *) malloc(BUFFER_SZ);
+    if (!buff) {
+       // printf("Error: Memory allocation failed.\n");
+        exit(99);
+    }
+
+    user_str_len = setup_buff(buff, input_string, BUFFER_SZ);     //see todos
+    if (user_str_len < 0){
+        //printf("Error setting up buffer, error = %d", user_str_len);
+        free(buff);
+        exit(2);
+    }
+
+    switch (opt){
+        case 'c':{
+            rc = count_words(buff, BUFFER_SZ, user_str_len);  //you need to implement
+            if (rc < 0){
+                printf("Error counting words, rc = %d", rc);
+                free(buff);
+                exit(2);
+            }
+            printf("Word Count: %d\n", rc);
+            print_buff(buff, BUFFER_SZ);
+            break;
+        }
+
+
+        //TODO:  #5 Implement the other cases for 'r' and 'w' by extending
+        //       the case statement options
+        case 'r':{
+            reverse_string(buff, user_str_len);
+           // printf("Reversed String: %.*s\n", user_str_len, buff);
+            print_buff(buff,BUFFER_SZ);
+            break;
+        }
+
+        case 'w':{
+            //printf("Word Print\n----------\n");
+            word_print(buff, user_str_len);
+            print_buff(buff,BUFFER_SZ);
+            break;
+        }
+        
+        case 'x': {
+            if (argc < 5) {
+            //printf("Not Implemented!\n");
+            free(buff);
+            exit(1);
+        }
+
+        char *find = argv[3];
+        char *replace = argv[4];
+
+        rc = string_replace(buff, BUFFER_SZ, find, replace);
+        if (rc == -2) {
+           // printf("Not Implemented!\n");
+            free(buff);
+            exit(3);
+        } else if (rc == -1) {
+           // printf("Not Implemented!\n");
+            free(buff);
+            exit(3);
+        }
+
+        // Print the buffer
+        printf("Buffer:  [");
+        for (int i = 0; i < BUFFER_SZ; i++) {
+            putchar(buff[i]);
+        }
+        printf("]\n");
+
+        //printf("Not Implemented!\n");
+        break;
+    }
+
+
+
+
+        default:
+            usage(argv[0]);
+            free(buff);
+            exit(1);
+    }
+
+    //TODO:  #6 Dont forget to free your buffer before exiting
+    //print_buff(buff,BUFFER_SZ);
+    free(buff);
+    //exit(0);
+    return 0;
+}
+
+//TODO:  #7  Notice all of the helper functions provided in the 
+//          starter take both the buffer as well as the length.  Why
+//          do you think providing both the pointer and the length
+//          is a good practice, after all we know from main() that 
+//          the buff variable will have exactly 50 bytes?
+//  
+//          PLACE YOUR ANSWER HERE
+
+/*
+Passing both the buffer pointer and its length to the helper functions 
+is considered good practice for several reasons:
+
+1. Code Resuable:
+    The functions become more general and reusable. They are not tied 
+    to a specific buffer size, allowing them to work with buffers 
+    of different sizes in other programs or contexts.
+
+2. Flexibility:
+    If the buffer size (BUFFER_SZ) changes in the future, the helper 
+    functions do not need to be modified. The updated size is passed 
+    automatically, making the code easier to maintain.
+
+3. Safety:
+    Explicitly passing the length ensures that the helper functions 
+    do not read or write beyond the allocated memory. This prevents 
+    buffer overflows, which could lead to undefined behavior or 
+    security vulnerabilities.
+
+4. Error Checking:
+    Having the buffer length allows the helper functions to validate 
+    inputs (e.g., ensuring the string length does not exceed the buffer 
+    size). This improves the program's robustness by catching errors early.
+
+5. Readable:
+    Including the buffer length makes it clear that the function 
+    operates on a fixed-size buffer and enforces constraints. 
+    It also serves as documentation for the function's behavior 
+    and expected input.
+*/
+
+