Skip to content
Snippets Groups Projects
Commit 8de727c4 authored by Charles Barnwell's avatar Charles Barnwell
Browse files

Upload New File

parent 0f53093d
Branches
No related tags found
No related merge requests found
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.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 reverse_str(char*, int, int);
int find_word(char *, char*);
int replace_word(char*, char*, char*, int, int);
int print_words(char*, int, int);
int setup_buff(char *buff, char *user_str, int len){
//TODO: #4: Implement the setup buff as per the directions
if (len > BUFFER_SZ) return -1;
int str_len = 0;
char *temp = buff;
while (*user_str == ' ') buff++; // skip leading spaces
while (*user_str != '\0' && str_len < len - 1) {
if (*user_str == ' ' && (*(user_str + 1) == ' ' || *(user_str + 1) == '\0')) {
user_str++;
continue;
}
*temp = *user_str;
temp++;
user_str++;
str_len++;
}
*temp = '\0';
return 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 (len < str_len || buff == NULL) return -1;
int ctr = 0;
bool counting = false;
while (*buff != '\0') {
if (*buff != ' ' && !counting) {
counting = true;
ctr++;
} else if (*buff == ' ' && counting) counting = false;
buff++;
}
return ctr;
}
//ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS
int reverse_str(char *buff, int buff_len, int str_len) {
if (buff_len == 0) {
printf("Empty String");
return -1;
}
char *end = buff;
while (*end != '\0') end++;
end--;
char *rev_str = malloc(sizeof(char) * (str_len + 1));
if (rev_str == NULL) {
printf("Memory allocation error\n");
return -1;
}
char *temp = rev_str;
while(end >= buff) {
*temp = *end;
temp++;
end--;
}
*temp = '\0';
printf("Reversed String: %s\n", rev_str);
free(rev_str);
return 0;
}
int find_word(char *buff, char *word) {
const char *b = buff;
const char *w = word;
int index = 0; // to track the starting index of the word
while (*b != '\0') {
if (*b == *w) {
const char *b_temp = b;
const char *w_temp = w;
while (*w_temp != '\0' && *b_temp == *w_temp) {
b_temp++;
w_temp++;
}
if (*w_temp == '\0') {
return index;
}
}
b++;
index++;
}
return -1; // word not found
}
int replace_word(char *buff, char *word, char *replacement, int buff_len, int str_len) {
if (str_len > buff_len || str_len == 0) return -2; // invalid input
int index = find_word(buff, word);
if (index == -1) return -1; // word doesn't exist in string
int word_len = 0;
while (word[word_len] != '\0') word_len++;
int replacement_len = 0;
while (replacement[replacement_len] != '\0') replacement_len++;
if (str_len - word_len + replacement_len > buff_len) return -3; // replcaement exceeds buffer size
if (replacement_len != word_len) {
char *end = buff + str_len;
char *src = buff + index + word_len;
char *dest = buff + index + replacement_len;
if (replacement_len > word_len) {
while (end >= src) {
*(dest--) = *(end--);
}
} else {
while (*src != '\0') {
*(dest++) = *(src++);
}
*dest = '\0';
}
}
char *replace_ptr = buff + index;
const char *replacement_ptr = replacement;
while (*replacement_ptr != '\0') *replace_ptr++ = *replacement_ptr++;
printf("Modified String: %s\n", buff);
return 0;
}
int print_words(char *buff, int buff_len, int str_len) {
if (str_len > buff_len) return -1;
if (str_len == 0) return 0;
int word_count = 0; // to start
int char_ctr = 0; // length of the current word
bool at_start = true; // if we are currently counting words
printf("Word Print\n----------\n");
while (*buff != '\0') {
if (*buff != ' ' && at_start) {
word_count++;
at_start = false; // we are processing a new word
printf("%d. ", word_count);
}
if (*buff == ' ' && !at_start) { // we hit the end of the word
printf(" (%d)\n", char_ctr); // length of the current word
char_ctr = 0; // start count for the next word
at_start = true; // we are starting a new word
} else { // we are just encountering a normal character
printf("%c", *buff); // current character
char_ctr++; // add to length of current string
}
buff++;
}
if (!at_start) printf(" (%d)\n", char_ctr); // this is for the last word
return word_count; // hold total number of words
}
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 argv[1] does not exist?
/*
Since argv[0] is the name of the executable, argv[1] is the first parameter used as input.
If argv[1] doesn't exist, then the program could run into problems. The code below prevents those.
*/
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
/*
If the number of arguments is less than 3 (including the executable's name),
print the usage of the program (the possible flags and input), then exit.
*/
if (argc < 3){
usage(argv[0]);
exit(1);
}
input_string = argv[2]; //capture the user input string
char *choice;
char *replacement;
if (opt == 'x') {
if (argc == 5) {
choice = argv[3];
replacement = argv[4];
} else {
printf("Error: invalid number of arguments");
exit(2);
}
}
//TODO: #3 Allocate space for the buffer using malloc and
// handle error if malloc fails by exiting with a
// return code of 99
buff = malloc(sizeof(char) * BUFFER_SZ);
if (buff == NULL) {
printf("Error setting up buffer");
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);
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 'r':
rc = reverse_str(buff, BUFFER_SZ, user_str_len);
if (rc < 0) {
printf("Error reversing words, rc = %d", rc);
exit(2);
}
break;
case 'w':
rc = print_words(buff, BUFFER_SZ, user_str_len);
if (rc < 0) {
printf("Error printing words, rc = %d", rc);
exit(2);
}
break;
case 'x':
rc = replace_word(buff, choice, replacement, BUFFER_SZ, user_str_len);
if (rc < 0) {
printf("Error replacing words, rc = %d", rc);
exit(2);
}
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?
//
// In a case where the global BUFFER_SZ variable is changed,
// you don't want the behavior of each of the functions to
// to be affacted negatively. Providing both the pointer to
// the buffer and the length is good so that the length is
// never in question for any individual function.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment