Skip to content
Snippets Groups Projects
Commit 8f0864a2 authored by dtt47's avatar dtt47
Browse files

update a1

parent 3b926323
No related branches found
No related tags found
No related merge requests found
#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);
int count_words(char *, int, int);
// add additional prototypes here
int reverse_string(char *, int, int);
int print_words(char *, int, int);
int replace_string(char *, char *, int, char *, char *);
int get_str_len(char *);
// Helper function for string length
int get_str_len(char *str)
{
char *ptr = str;
while (*ptr)
ptr++;
return ptr - str;
}
int setup_buff(char *buff, char *user_str, int len)
{
if (!buff || !user_str)
return -2;
char *src = user_str;
char *dst = buff;
int count = 0;
int space_seen = 1; // Start true to handle leading spaces
// Skip leading whitespace
while (*src == ' ' || *src == '\t')
src++;
// Copy and process the string
while (*src != '\0')
{
if (count >= len)
return -1;
if (*src == ' ' || *src == '\t')
{
if (!space_seen && *(src + 1) != '\0')
{
*dst++ = ' ';
count++;
space_seen = 1;
}
}
else
{
*dst++ = *src;
count++;
space_seen = 0;
}
src++;
}
// Remove trailing space if it exists
if (count > 0 && *(dst - 1) == ' ')
{
dst--;
count--;
}
// Pad with dots
while (count < len)
{
*dst++ = '.';
count++;
}
return count - (buff + len - dst);
}
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 (!buff || str_len <= 0 || str_len > len)
return -1;
char *ptr = buff;
int count = 0;
int in_word = 0;
while (ptr < buff + str_len)
{
if (*ptr != ' ' && !in_word)
{
count++;
in_word = 1;
}
else if (*ptr == ' ')
{
in_word = 0;
}
ptr++;
}
return count;
}
// ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS
int reverse_string(char *buff, int len, int str_len)
{
if (!buff || str_len <= 0 || str_len > len)
return -1;
char *start = buff;
char *end = buff + str_len - 1;
char temp;
while (start < end)
{
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
return 0;
}
int print_words(char *buff, int len, int str_len)
{
if (!buff || str_len <= 0 || str_len > len)
return -1;
char *start = buff;
char *current = buff;
int word_count = 0;
int word_len;
printf("Word Print\n----------\n");
while (current < buff + str_len)
{
while (current < buff + str_len && *current == ' ')
{
current++;
}
if (current >= buff + str_len)
break;
start = current;
word_len = 0;
while (current < buff + str_len && *current != ' ')
{
word_len++;
current++;
}
if (word_len > 0)
{
word_count++;
printf("%d. ", word_count);
char *temp = start;
while (temp < start + word_len)
{
putchar(*temp);
temp++;
}
printf(" (%d)\n", word_len);
}
}
printf("Number of words returned: %d\n", word_count);
return word_count;
}
int replace_string(char *buff, int len, int str_len, char *search, char *replace)
{
if (!buff || !search || !replace || str_len <= 0 || str_len > len)
return -1;
char *current = buff;
char *end = buff + str_len;
int search_len = get_str_len(search);
int replace_len = get_str_len(replace);
// Find search string
int found = 0;
while (current < end - search_len + 1)
{
char *s1 = current;
char *s2 = search;
int match = 1;
for (int i = 0; i < search_len; i++)
{
if (*s1++ != *s2++)
{
match = 0;
break;
}
}
if (match)
{
found = 1;
break;
}
current++;
}
if (!found)
return -2;
// Calculate new length
int new_len = str_len - search_len + replace_len;
if (new_len > len)
return -3;
// Shift content if needed
if (replace_len != search_len)
{
char *src = current + search_len;
char *dst = current + replace_len;
if (replace_len > search_len)
{
char *src_end = end - 1;
char *dst_end = src_end + (replace_len - search_len);
while (src_end >= src)
{
*dst_end-- = *src_end--;
}
}
else
{
while (src < end)
{
*dst++ = *src++;
}
}
}
// Copy replacement
char *replace_ptr = replace;
while (*replace_ptr)
{
*current++ = *replace_ptr++;
}
// Update dots
char *dot_start = buff + new_len;
while (dot_start < buff + len)
{
*dot_start++ = '.';
}
return new_len;
}
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?
// PLACE A COMMENT BLOCK HERE EXPLAINING
/* This is safe because we check argc < 2 before accessing argv[1].
* If there aren't enough arguments, we exit before attempting to
* access argv[1], preventing any buffer overrun.
*/
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
// PLACE A COMMENT BLOCK HERE EXPLAINING
/* This ensures we have enough arguments for all operations except help.
* Every operation needs at least program name, option, and input string,
* so we need at least 3 arguments.
*/
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)
{
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);
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);
free(buff);
exit(2);
}
printf("Word Count: %d\n", rc);
break;
case 'r':
rc = reverse_string(buff, BUFFER_SZ, user_str_len);
if (rc < 0)
{
printf("Error reversing string\n");
free(buff);
exit(3);
}
break;
case 'w':
rc = print_words(buff, BUFFER_SZ, user_str_len);
if (rc < 0)
{
printf("Error printing words\n");
free(buff);
exit(3);
}
break;
case 'x':
if (argc != 5)
{
printf("Error: -x requires search and replace strings\n");
free(buff);
exit(1);
}
rc = replace_string(buff, BUFFER_SZ, user_str_len, argv[3], argv[4]);
if (rc < 0)
{
switch (rc)
{
case -1:
printf("Error: Invalid parameters\n");
break;
case -2:
printf("Error: Search string not found\n");
break;
case -3:
printf("Error: Replacement would exceed buffer size\n");
break;
}
free(buff);
exit(3);
}
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?
//
/* Passing both pointer and length is good practice because:
* 1. Prevents buffer overflows through bounds checking
* 2. Makes functions reusable with different buffer sizes
* 3. Follows principle of least privilege
* 4. Makes code more maintainable if buffer size changes
* 5. Helps catch programming errors through explicit length checks
*/
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment