diff --git a/assignments/assignment-1/starter/stringfun b/assignments/assignment-1/starter/stringfun new file mode 100755 index 0000000000000000000000000000000000000000..bef77fbfd58283f303089b1b55b44ac8b7ca55f3 Binary files /dev/null and b/assignments/assignment-1/starter/stringfun differ diff --git a/assignments/assignment-1/starter/stringfun.c b/assignments/assignment-1/starter/stringfun.c index 1020f7ef2dd6f6a832ae7d39af9a6ad98fae8a80..3471e29cdc2094f2141434a50898aae04cfb682f 100644 --- a/assignments/assignment-1/starter/stringfun.c +++ b/assignments/assignment-1/starter/stringfun.c @@ -12,12 +12,71 @@ int setup_buff(char *, char *, int); //prototypes for functions to handle required functionality int count_words(char *, int, int); -//add additional prototypes here +//add additional prototypes here +void word_print(char *buff, int len); +void reverse_print(char *buff, int len); int setup_buff(char *buff, char *user_str, int len){ //TODO: #4: Implement the setup buff as per the directions - return 0; //for now just so the code compiles. + // Calculate the length of the string the user put into the program + int user_str_length = 0; + char *temp_str = user_str; + + // Iterate through the string to find the null terminator so we can see how long the string is + while (*temp_str != '\0') { + user_str_length++; + temp_str++; + } + + // Return an error code if the inputted string is bigger than the buffer size + if (user_str_length > len) { + fprintf(stderr, "The input string you gave is too long\n"); + return(-1); + } + + // Initialize pointers + char *buff_ptr = buff; + char *user_str_ptr = user_str; + int consec_spaces = 0; + + // Go through the string and copy the characters to the buffer + while (*user_str_ptr != '\0') { + + char current_char = *user_str_ptr; + + // Check to see if the current character is a space or a tab + if (current_char == ' ' || current_char == '\t') { + + // This will add a single space if it's not a consecutive whitespace + if (!consec_spaces && buff_ptr != buff) { + *buff_ptr = ' '; + buff_ptr++; + } + + // Set the flag for the consecutive spaces + consec_spaces = 1; + + } + // Copy the character to the buffer, move the buffer pointer to the next position, and reset the consecutive space flag + else { + *buff_ptr = current_char; + buff_ptr++; + consec_spaces = 0; + } + + // Move to the next character in the user string + user_str_ptr++; + } + + // Fill the remaining buffer spaces with . + while (buff_ptr < buff + len) { + *buff_ptr = '.'; + buff_ptr++; + } + + // Return the length of the user string + return user_str_length; } void print_buff(char *buff, int len){ @@ -34,12 +93,117 @@ void usage(char *exename){ } int count_words(char *buff, int len, int str_len){ - //YOU MUST IMPLEMENT - return 0; + // Check to make sure the user string is larger than the buffer size + if (str_len > len) { + printf("User input is larger than the buffer size.\n"); + return -3; + } + + // Initialize counters for words and a flag to tell if we're in a word + int word_count = 0; + int in_a_word = 0; + + // Iterate through the buffer until we reach the end of the user string + for (int i = 0; i < str_len; i++) { + + // Get the currect character from the buffer + char current_char = *(buff + i); + + // Check if the current character is a space or tab + if (current_char == ' ' || current_char == '\t') { + // Reset in a word flag if it's a space or tab + in_a_word = 0; + } + else { + // If we weren't in a word and we see a non-whitespace character, start a new word and increment the word count + if (in_a_word == 0) { + word_count++; + } + + // Set the flag to indicate we are inside a word + in_a_word = 1; + } + } + + // Print the final word count and return the word count + printf("Word Count: %d\n", word_count); + return word_count; } //ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS +void word_print(char *buff, int len) { + // Initial prints to set up the format + printf("Word Print\n"); + printf("----------\n"); + + // Initialize variables and pointers for the start of the current word, length of the current word, and the count for the number of words + char *start_of_word = NULL; + int word_length = 0; + int word_count = 1; + + // Iterate over each character in the buffer + for (int i = 0; i < len; i++) { + // Check if the current character is actually a character + if(*(buff + i) != ' ' && *(buff + i) != '.' && *(buff + i) != '\0') { + // Mark the start of the word + if (start_of_word == NULL) { + start_of_word = buff + i; + } + // Increment the word length because we're inside a word + word_length++; + } + + // If we encounter non-character and we're currently inside of a word + else if (start_of_word != NULL) { + // Print the word count and the word itself + printf("%d. ", word_count++); + + // Print the characters of the current word + for (int j = 0; j < word_length; j++) { + printf("%c", *(start_of_word + j)); + } + + // Print the length of the word + printf(" (%d)\n", word_length); + + // Reset for the next word + start_of_word = NULL; + word_length = 0; + } + } + + // If the loop ends and there's still a word being processed, print the word + if (start_of_word != NULL) { + printf("%d. ", word_count); + + for (int j = 0; j < word_length; j++) { + printf("%c", *(start_of_word + j)); + } + + printf(" (%d)\n", word_length); + } +} + +void reverse_print(char *buff, int len) { + // Give an error message if the buffer length is 0 (there's no word) + if (len == 0) { + printf("Error: The string you put in is empty and we can't reverse it\n"); + exit(3); + } + + // Initial print to setup the format + printf("Reversed String: "); + + // Loop through the buffer starting from the last character moving backwards and printing it so it prints in reverse + for (int i = len - 1; i >= 0; i--) { + printf("%c", *(buff + i)); + } + + // Prints a new line after reversing + printf("\n"); +} + int main(int argc, char *argv[]){ char *buff; //placehoder for the internal buffer @@ -50,6 +214,15 @@ int main(int argc, char *argv[]){ //TODO: #1. WHY IS THIS SAFE, aka what if arv[1] does not exist? // PLACE A COMMENT BLOCK HERE EXPLAINING + /* + * The reason that this if statement is safe is because it checks to see how many command line arguments there are before trying to access them. + * If there are less than 2 command line arguments, that means that the command is incomplete, so when we go to access it, there might be unintended behavior that we may not have accounted for. + * Since the program checks before accessing it, it will exit the command before we even try to use it, so that unintended behavior will never happen. + * If there are 2 or more arguments though, it will make sure that the 2nd command line input has a - in it, as that is what is used to call the different functions. + * If it doesn't, it will follow the same fate as if you don't have 2 or more command line arguments. + * It will exit the program with a command line failure code. + */ + if ((argc < 2) || (*argv[1] != '-')){ usage(argv[0]); exit(1); @@ -67,6 +240,11 @@ int main(int argc, char *argv[]){ //TODO: #2 Document the purpose of the if statement below // PLACE A COMMENT BLOCK HERE EXPLAINING + /* + * This is the same thing as the previous TODO if statement, except this will run after the first check already happens. + * If there are 2 or more command line arguments, and the 2nd one has a - in it, then it will check to see if there are 3 command line arguments. + * This check is to make sure taht there is a sample string passed along. If there isn't, it will exit with code 1 to indicate a command line error. + */ if (argc < 3){ usage(argv[0]); exit(1); @@ -78,7 +256,15 @@ int main(int argc, char *argv[]){ // handle error if malloc fails by exiting with a // return code of 99 // CODE GOES HERE FOR #3 + + buff = (char *)malloc(BUFFER_SZ); + // Check to make sure the malloc worked properly + + if(buff == NULL) { + fprintf(stderr, "Memory allocation failure\n"); + exit(99); + } user_str_len = setup_buff(buff, input_string, BUFFER_SZ); //see todos if (user_str_len < 0){ @@ -98,13 +284,30 @@ int main(int argc, char *argv[]){ //TODO: #5 Implement the other cases for 'r' and 'w' by extending // the case statement options + + // Call reverse_print when user inputs -r + case 'r': + reverse_print(buff, user_str_len); + break; + + // Call word_print when user inputs -w + case 'w': + word_print(buff, user_str_len); + break; + default: usage(argv[0]); exit(1); } //TODO: #6 Dont forget to free your buffer before exiting + + // Print the entire buffer after a user inputs the command line argument call print_buff(buff,BUFFER_SZ); + + // Free memory + free(buff); + exit(0); } @@ -114,4 +317,11 @@ int main(int argc, char *argv[]){ // is a good practice, after all we know from main() that // the buff variable will have exactly 50 bytes? // -// PLACE YOUR ANSWER HERE \ No newline at end of file +// PLACE YOUR ANSWER HERE +// + +/* + * Since we are giving the functions both the buffer and the length of it, it lets us have it just incase we need it for error preventions. + * You could use the length of the buffer to double check that the length of the user string is still within range of the buffer, just incase anything happened to it from when we first checked it to the function. + * For example, if we decide to change the buffer size to something more flexible, it will be sent out to all the functions to again, check to make sure that it still fits. +*/