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