From 6883e1b192bda14d403a4731f472b92ef0438c7d Mon Sep 17 00:00:00 2001 From: Bao Mai <bgm47@drexel.edu> Date: Sun, 19 Jan 2025 22:30:43 -0500 Subject: [PATCH] update assignment 1 --- 1-C-Refresher/stringfun.c | 252 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 1-C-Refresher/stringfun.c diff --git a/1-C-Refresher/stringfun.c b/1-C-Refresher/stringfun.c new file mode 100644 index 0000000..1c74d56 --- /dev/null +++ b/1-C-Refresher/stringfun.c @@ -0,0 +1,252 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define BUFFER_SZ 50 + +//prototypes +void usage(char *); +void print_buff(char *, int); +int setup_buff(char *, char *, int); +int count_words(char *, int, int); +void reverse(char *, int, int); +void printw(char *, int, int); +void srplace(char *, int, char *, char *, int); + +//prototypes for functions to handle required functionality +int count_words(char *buff, int len, int str_len) { + int word_count = 0; + int in_word = 0; + + for (int i = 0; i < str_len; i++) { + if (*(buff + i) != ' ') { + if (!in_word) { + in_word = 1; + word_count++; + } + } else { + in_word = 0; + } + } + + return word_count; +} + +int setup_buff(char *buff, char *user_str, int len) { + char *src = user_str; + char *dest = buff; + int count = 0; + int space_flag = 0; + while (*src != '\0' && count < len) { + if (*src == ' ' || *src == '\t') { + if (!space_flag) { + *dest++ = ' '; + count++; + space_flag = 1; + } + } else { + *dest++ = *src; + count++; + space_flag = 0; + } + src++; + } + if (*src != '\0') { + return -1; + } + while (count < len) { + *dest++ = '.'; + count++; + } + return count; +} + +void print_buff(char *buff, int len) { + printf("Buffer: ["); + for (int i = 0; i < len; i++) { + putchar(*(buff + i)); + } + printf("]\n"); +} + +void usage(char *exename) { + printf("usage: %s [-h|c|r|w|x] \"string\" [other args]\n", exename); +} + +void reverse(char *buff, int len, int str_len) { + char *start = buff; + char *end = buff + str_len - 1; + char temp; + + while (start < end) { + temp = *start; + *start = *end; + *end = temp; + start++; + end--; + } +} + +void printw(char *buff, int len, int str_len) { + int word_index = 1; + int word_length = 0; + + printf("Word Print\n----------\n"); + + for (int i = 0; i < str_len; i++) { + char current_char = *(buff + i); + if ((current_char >= 'A' && current_char <= 'Z') || + (current_char >= 'a' && current_char <= 'z') || + (current_char >= '0' && current_char <= '9')) { + + if (word_length == 0) { + printf("%d. ", word_index); + } + putchar(current_char); + word_length++; + } else if (current_char == ' ' && word_length > 0) { + printf("(%d)\n", word_length); + word_index++; + word_length = 0; + } + } + if (word_length > 0) { + printf(" (%d)\n", word_length); + } + + printf("\nNumber of words returned: %d\n", word_index); +} + + + +void srplace(char *buff, int len, char *old, char *new, int str_len) { + char temp[BUFFER_SZ]; + char *src = buff, *dest = temp; + int old_len = strlen(old), new_len = strlen(new); + int replaced = 0; + + while (*src != '\0' && (dest - temp) < BUFFER_SZ) { + if (strncmp(src, old, old_len) == 0) { + if ((dest - temp) + new_len > BUFFER_SZ) { + break; // Prevent overflow + } + strncpy(dest, new, new_len); + src += old_len; + dest += new_len; + replaced = 1; + } else { + *dest++ = *src++; + } + } + + while ((dest - temp) < BUFFER_SZ) { + *dest++ = '.'; + } + + if (replaced) { + memcpy(buff, temp, BUFFER_SZ); + } else { + printf("Not Implemented!\n"); + exit(1); + } +} + +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 done to make that the command has the right syntax and all the minimal arguments + //needed for the subsequent operations to run with valid inputs, or to specify the type of error + //so the user may rectify it and find the right command that will work. + if ((argc < 2) || (*argv[1] != '-')){ + usage(argv[0]); + exit(1); + } + + opt = (char)*(argv[1]+1); + + //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 + //It ensures that the user enters a command with at least one flag and two required parameters + //to proceed. Otherwise, an error will occur, and the syntax will assist them enter the right 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 + buff = (char *)malloc(BUFFER_SZ); + if (buff == NULL) { + exit(99); + } + + user_str_len = setup_buff(buff, input_string, BUFFER_SZ); + if (user_str_len < 0) { + printf("Error setting up buffer\n"); + 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); + exit(2); + } + printf("Word Count: %d\n", rc); + break; + case 'r': + reverse(buff, BUFFER_SZ, user_str_len); + break; + case 'w': + printw(buff, BUFFER_SZ, user_str_len); + break; + + case 'x': + if (argc < 5) { + usage(argv[0]); + free(buff); + exit(1); + } + srplace(buff, BUFFER_SZ, argv[3], argv[4], user_str_len); + 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); +} + +//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? +// +// Both the pointer and the length must be provided since this +// will enable the function to monitor the buffer's length during and after each +// modification step to prevent overflow and to set up the buffer once the string +// operation is finished (ensuring that it always contains exactly 50 bytes). \ No newline at end of file -- GitLab