From f7e566e033b7053f4fd67d397bd87893a585102d Mon Sep 17 00:00:00 2001
From: vyvyvyThao <wn73@drexel.edu>
Date: Sun, 19 Jan 2025 19:35:45 -0500
Subject: [PATCH] assignment 1

---
 1-C/stringfun.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 354 insertions(+)
 create mode 100644 1-C/stringfun.c

diff --git a/1-C/stringfun.c b/1-C/stringfun.c
new file mode 100644
index 0000000..66671d7
--- /dev/null
+++ b/1-C/stringfun.c
@@ -0,0 +1,354 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#define BUFFER_SZ 50
+
+//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
+int wordPrint(char *buff, char user_str_len);
+void reverse(char *buff, int user_str_len);
+int wordFound(char *str, char *word);
+int replace(char *src, char *word, char *replacement, char *dest, int buff_len);
+
+
+int setup_buff(char *buff, char *user_str, int len){
+    //TODO: #4:  Implement the setup buff as per the directions
+    /*
+    - Make all white spaces single space
+    - Count the length
+    - Return -1 if length > BUFFER_SZ
+    - Else: fill dots in and return length
+    */
+    int space = 0;
+    int user_str_len = 0;
+
+    while (*user_str != '\0' && user_str_len <= len) {
+        if (*user_str != ' ') {
+            *buff = *user_str;
+            buff++;
+            space = 0;
+            user_str_len++;
+
+        } else {
+            if (space == 0) {
+                *buff = *user_str;
+                buff++;
+                user_str_len++;
+                space += 1;
+            }
+        }
+        user_str++;
+    }
+
+    if (*user_str != '\0' && user_str_len > len) {
+        return -1;
+    }
+
+    int buff_curr_len = user_str_len;
+
+    while (buff_curr_len < len) {
+        *buff = '.';
+        buff++;
+        buff_curr_len++;
+    }
+
+    buff =  buff - buff_curr_len;
+
+    return user_str_len;  
+}
+
+void print_buff(char *buff, int len){
+    printf("Buffer:  ");
+    for (int i=0; i<len; i++){
+        putchar(*(buff+i));
+    }
+    putchar('\n');
+}
+
+void usage(char *exename){
+    printf("usage: %s [-h|c|r|w|x] \"string\" [other args]\n", exename);
+
+}
+
+int count_words(char *buff, int len, int str_len){
+    if (str_len == 0) {
+        return 0;
+    }
+
+    int wc = 0;
+    for (int i = 0; i < str_len; i++) {
+        if (*buff == ' ') {
+            wc += 1;
+        }
+        buff++;
+    }
+    wc += 1;
+
+    return wc;
+}
+
+//ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS
+
+int wordPrint(char *buff, char user_str_len) {
+    int charCount = 0;
+    int wordCount = 1;
+    printf("Word Print \n----------\n");
+    printf("%d. ", wordCount);
+
+    while (*buff != '.') {
+        if (*buff != ' ') {
+            printf("%c", *buff);
+            charCount++;
+        } else {
+            printf(" (%d)\n", charCount);
+            charCount = 0;
+            wordCount++;
+            printf("%d. ", wordCount);
+        } 
+
+        buff++;
+    }
+
+    printf(" (%d)\n", charCount);
+    printf("Number of words returned: %d\n", wordCount);
+
+    buff = buff - user_str_len;
+}
+
+void reverse(char *buff, int user_str_len) {
+    char temp;
+    char *end = buff + user_str_len - 1;
+
+    while (end > buff) {
+        temp = *buff;
+        *buff = *end;
+        *end = temp;
+        end--;
+        buff++; 
+    }
+}
+
+int wordFound(char *str, char *word) {
+    int wordLength = 0;
+
+    while (*word != '\0') {
+        if (*str != *word) {
+            return 0;   // first word in string is not the wanted word
+        }
+        wordLength++;
+        str++;
+        word++;
+    }
+
+    word = word - wordLength;
+    if (*str != ' ' && *str != '\0' && *str != '.') {
+        return 0;
+    }
+    str = str - wordLength;
+    return wordLength;
+}
+
+int replace(char *src, char *word, char *replacement, char *dest, int buff_len) {
+    int match;
+    int newWord = 1;
+    char * original_dst = dest;
+    int destLength = 0;
+    int replmLength = 0;
+
+    int wordNotFound = 1;
+
+    while (*replacement != '\0') {
+        replmLength++;
+        replacement++;
+    } 
+
+    replacement = replacement - replmLength;
+
+    while (*src != '.') {
+        if (newWord) {
+            match = wordFound(src, word);
+
+            // if word to replace is found, copy replacement to dest instead
+            if (match > 0) {
+                wordNotFound = 0;
+                while (*replacement != '\0') {
+                    destLength++;
+                    if (destLength > buff_len) {
+                        return -1;
+                    }
+                    
+                    *dest = *replacement;
+                    dest++;
+                    replacement++;
+                }
+                src = src + match;
+                replacement = replacement - replmLength;
+            }
+        }
+
+        if (*src == '.') {
+            break;
+        }
+
+        destLength++;
+        if (destLength > buff_len) {
+            return -1;
+        }
+        *dest = *src;
+
+        if (*src == ' ') {
+            newWord = 1;
+        } else {
+            newWord = 0;
+        }
+        dest++;
+        src++;
+    }
+
+    if (wordNotFound) {
+        return 1;
+    }
+
+    dest = dest - destLength;
+    // printf("Replaced string: %s\n", dest);
+
+    
+    return destLength;
+}
+
+int main(int argc, char *argv[]){
+
+    char *buff;             //placehoder for the internal buffer
+    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?
+    //      This is to validate if the command has a correct syntax and all minimum required arguments
+    //      so that the following operations can run with valid inputs or the type of error can be
+    //      specified to help the user fix it and find the correct command that is going to work
+    if ((argc < 2) || (*argv[1] != '-')){
+        usage(argv[0]);
+        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]);
+        exit(0);
+    }
+
+    //WE NOW WILL HANDLE THE REQUIRED OPERATIONS
+
+    //TODO:  #2 Document the purpose of the if statement below
+    //      The if statement below is to make sure the user 
+    //      uses a command with at least 1 flag and 2 required
+    //      arguments to proceed. Otherwise, an error will 
+    //      occur and the syntax will be provided to help them
+    //      enter the correct command
+
+    if (argc < 3){
+        usage(argv[0]);
+        exit(1);
+    }
+
+    input_string = argv[2]; //capture the user input string
+
+    //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
+    buff = malloc(sizeof(char)*BUFFER_SZ);
+
+
+    user_str_len = setup_buff(buff, input_string, BUFFER_SZ);     //see todos
+
+    
+    if (user_str_len < 0){
+        printf("Error setting up buffer, error = %d\n", user_str_len);
+        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);
+                exit(2);
+            }
+            printf("Word Count: %d\n", rc);
+            break;
+
+        //TODO:  #5 Implement the other cases for 'r' and 'w' by extending
+        //       the case statement options
+
+        case 'w':
+            wordPrint(buff, user_str_len);
+            break;
+
+        case 'r':
+            reverse(buff, user_str_len);
+            break;
+
+        case 'x':
+            if (argc < 5) {
+                printf("Not Implemented!\n");
+                exit(1); 
+            }
+
+            char *word = argv[3];           // word to replace
+            char *replacement = argv[4]; 
+            
+            char *dest = malloc(sizeof(char) * 50);
+
+            int destLenght = replace(buff, word, replacement, dest, BUFFER_SZ);
+            if (destLenght == -1) {
+                printf("Not implemented! Replacement is causing buffer overflow.\n");
+                exit(2);    // overflow error
+            }
+
+            if (destLenght == 1) {
+                printf("Not implemented! Word not found.\n");
+                exit(3);    // error with provided service
+            }
+
+            user_str_len = setup_buff(buff, dest, BUFFER_SZ);
+            free(dest);
+
+            break;
+
+        default:
+            usage(argv[0]);
+            exit(1);
+    }
+    
+
+    //TODO:  #6 Dont forget to free your buffer before exiting
+    print_buff(buff,BUFFER_SZ);
+    free(buff);
+    exit(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?
+//  
+//          Providing both the pointer and the length is necessary
+//          because it will help the function keep track of the length
+//          of the buffer while and after each step of modification
+//          to avoid overflow as well as to set up the buffer after
+//          the string operation is complete (so that it always has
+//          exactly 50 bytes)  
\ No newline at end of file
-- 
GitLab