Select Git revision
D4-WebScrape_Fixed.ipynb
stringfun.c 4.63 KiB
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.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_string(char *, int);
void word_print(char *, int, int);
int setup_buff(char *buff, char *user_str, int len) { //TODO: #4: Implemented the setup buff as per the directions
char *b_ptr = buff;
char *u_ptr = user_str;
int user_len = 0;
bool last_was_space = false;
while (*u_ptr != '\0') {
if (user_len >= len) {
return -1; // Error: Input string exceeds buffer size
}
if (*u_ptr == ' ' || *u_ptr == '\t') {
if (!last_was_space) {
*b_ptr = ' ';
b_ptr++;
user_len++;
last_was_space = true;
}
} else {
*b_ptr = *u_ptr;
b_ptr++;
user_len++;
last_was_space = false;
}
u_ptr++;
}
while (user_len < len) {
*b_ptr = '.';
b_ptr++;
user_len++;
}
return user_len;
}
int count_words(char *buff, int len, int str_len) {
if (str_len > len) {
return -1; // Error: String length exceeds buffer size
}
int word_count = 0;
bool at_start = true;
for (int i = 0; i < str_len; i++) {
char c = *(buff + i);
if (at_start && c != ' ') {
word_count++;
at_start = false;
} else if (c == ' ') {
at_start = true;
}
}
return word_count;
}
void reverse_string(char *buff, int str_len) {
for (int i = 0, j = str_len - 1; i < j; i++, j--) {
char temp = *(buff + i);
*(buff + i) = *(buff + j);
*(buff + j) = temp;
}
}
void word_print(char *buff, int len, int str_len) {
printf("Word Print\n----------\n");
int word_start = 0;
for (int i = 0; i <= str_len; i++) {
if (i == str_len || *(buff + i) == ' ') {
printf("%.*s (%d)\n", i - word_start, buff + word_start, i - word_start);
word_start = i + 1;
}
}
}
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 main(int argc, char *argv[]) {
char *buff;
char *input_string;
char opt;
int rc;
int user_str_len;
// TODO: #1 Explain why this is safe
// This ensures that argv[1] exists and starts with '-'. If not, the program exits.
if ((argc < 2) || (*argv[1] != '-')) {
usage(argv[0]);
exit(1);
}
opt = (char) *(argv[1] + 1); // Get the option flag
if (opt == 'h') {
usage(argv[0]);
exit(0);
}
// TODO: #2 Explain the purpose of this check
// This ensures the user provided a string as the second argument (argv[2]).
if (argc < 3) {
usage(argv[0]);
exit(1);
}
input_string = argv[2]; // Capture user input string
// TODO: #3 Allocate buffer and handle memory allocation failure
buff = (char *) malloc(BUFFER_SZ);
if (buff == NULL) {
printf("Error: Memory allocation failed.\n");
exit(99);
}
user_str_len = setup_buff(buff, input_string, BUFFER_SZ);
if (user_str_len < 0) {
printf("Error setting up buffer, error = %d\n", user_str_len);
free(buff);
exit(2);
}
switch (opt) {
case 'c': // Word count
rc = count_words(buff, BUFFER_SZ, user_str_len);
if (rc < 0) {
printf("Error counting words, rc = %d\n", rc);
free(buff);
exit(2);
}
printf("Word Count: %d\n", rc);
break;
//TODO: #5 Implemented the other cases for 'r' and 'w' by extending
//the case statement options
case 'r': // Reverse string
reverse_string(buff, user_str_len);
printf("Reversed String: %.*s\n", user_str_len, buff);
break;
case 'w': // Word print
word_print(buff, BUFFER_SZ, user_str_len);
break;
default:
usage(argv[0]);
free(buff);
exit(1);
}
// TODO: #6 Free the buffer before exiting
free(buff);
exit(0);
}
// TODO: #7 Answer
// Providing both the pointer and length ensures safer processing, as functions
// cannot assume strings are null-terminated or rely on external constraints.
// This minimizes memory-related errors.