Skip to content
Snippets Groups Projects
Commit f4f730e3 authored by Andrew To's avatar Andrew To
Browse files

HW2

parent 8aeed05f
No related branches found
No related tags found
No related merge requests found
.DS_Store 0 → 100644
File added
# Compiler settings
CC = gcc
CFLAGS = -Wall -Wextra -g
# Target executable name
TARGET = stringfun
# Default target
all: $(TARGET)
# Compile source to executable
$(TARGET): stringfun.c
$(CC) $(CFLAGS) -o $(TARGET) $^
# Clean up build files
clean:
rm -f $(TARGET)
# Phony targets
.PHONY: all clean
\ No newline at end of file
File added
#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 setup_buff(char *buff, char *user_str, int len){
//TODO: #4: Implement the setup buff as per the directions
bool isSpace = false;
int count = 0;
while (*user_str != '\0' && count < BUFFER_SZ - 1) { // stop when reaching the end-of-buffer
if (*user_str != '\t'){
if (*user_str != ' ' || isSpace == false) {
*buff = *user_str;
if (*user_str == ' '){
isSpace = true;
} else {
isSpace = false;
}
buff++;
user_str++;
count++;
} else {
user_str++;
isSpace = false;
}
} else {
user_str++;
}
}
int ret = count;
if (count > len){
return -1;
}
while (count <= len){
*buff = '.';
buff++;
count++;
}
return ret; //for now just so the code compiles.
}
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){
//YOU MUST IMPLEMENT
if (str_len > len){
return -1;
}
if (str_len==0){
return 0;
}
int words = 1;
for (int i=0; i<str_len; i++){
if (*buff == ' '){
words++;
}
buff++;
}
return words;
}
//ADD OTHER HELPER FUNCTIONS HERE FOR OTHER REQUIRED PROGRAM OPTIONS
void reverse_string(char *buff, int len, int str_len){
int lim;
if (len < str_len){
lim = len;
} else {
lim = str_len;
}
char *newBuff = (char*)malloc(BUFFER_SZ);
for (int i=0; i<lim; i++){
*newBuff = *buff;
newBuff--;
buff++;
}
for (int i=0; i<lim; i++){
putchar(*(newBuff+i));
}
printf("\n");
}
void word_print(char *buff, int len, int str_len){
int lim;
if (len < str_len){
lim = len;
} else {
lim = str_len;
}
int count = 1;
int track = 0;
printf("Word Print\n");
printf("--------------\n");
printf("%d. ", count);
for (int i=0; i<lim; i++){
if (*buff != ' '){
putchar(*buff);
track++;
} else {
printf(" (%d)\n",track);
count++;
printf("%d. ", count);
track = 0;
}
buff++;
}
printf(" (%d)\n",track);
}
// void replace(char *buff, *new_buff)
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
/*
If arv[1] does not exist, the condition argc < 2, so the program will safely exit and print the usage:
usage: ./stringfun [-h|c|r|w|x] "string" [other args]
*/
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 if statement make sure that users provide a string after the namefile and the operation (-h|c|r|w|x)
If not, it will print the usage
*/
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
// CODE GOES HERE FOR #3
buff= (char*)malloc(BUFFER_SZ);
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':
reverse_string(buff, BUFFER_SZ, user_str_len);
break;
case 'w':
word_print(buff, BUFFER_SZ, user_str_len);
break;
case 'x':
if (argc < 5){
printf("Need 3 arguments: sample string and 2 other strings\n");
exit(1);
} else {
// buff= (char*)malloc(BUFFER_SZ);
// old_string = argv[3];
// old_str_len = setup_buff()
// new_string = argv[4];
// new_str_len = setup_buff(buff, new_string, BUFFER_SZ);
printf("Not Implemented\n");
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?
//
// PLACE YOUR ANSWER HERE
//
// We need the pointer to access and modify the values in the address.
// Providing the length is a good practice since we sometimes need to
// use the length (of the buffer and the user string) to make sure that
// there is no buffer overflow or similiar errors appear in our function.
\ No newline at end of file
#!/usr/bin/env bats
@test "no args shows usage" {
run ./stringfun
[ "$status" -eq 1 ]
[ "${lines[0]}" = "usage: ./stringfun [-h|c|r|w|x] \"string\" [other args]" ]
}
@test "bad args shows usage" {
run ./stringfun -z "Bad arg usage"
[ "$status" -eq 1 ]
[ "${lines[0]}" = "usage: ./stringfun [-h|c|r|w|x] \"string\" [other args]" ]
}
@test "check -h" {
run ./stringfun -h
[ "$status" -eq 0 ]
[ "${lines[0]}" = "usage: ./stringfun [-h|c|r|w|x] \"string\" [other args]" ]
}
@test "wordcount" {
run ./stringfun -c "There should be eight words in this sentence"
[ "$status" -eq 0 ]
[ "$output" = "Word Count: 8
Buffer: [There should be eight words in this sentence......]" ]
}
@test "remove extra spaces" {
run ./stringfun -c " The strange spaces should be removed from this "
[ "$status" -eq 0 ]
[ "$output" = "Word Count: 8
Buffer: [The strange spaces should be removed from this....]" ]
}
@test "reverse" {
run ./stringfun -r "Reversed sentences look very weird"
[ "$status" -eq 0 ]
[ "$output" = "Buffer: [driew yrev kool secnetnes desreveR................]" ]
}
@test "print words" {
run ./stringfun -w "Lets get a lot of words to test"
[ "$status" -eq 0 ]
[ "$output" = "Word Print
----------
1. Lets(4)
2. get(3)
3. a(1)
4. lot(3)
5. of(2)
6. words(5)
7. to(2)
8. test(4)
Number of words returned: 8
Buffer: [Lets get a lot of words to test...................]" ]
}
@test "check max length" {
run ./stringfun -r "This is the maximum length string that should work"
[ "$status" -eq 0 ]
[ "$output" = "Buffer: [krow dluohs taht gnirts htgnel mumixam eht si sihT]" ]
}
@test "check over max length" {
run ./stringfun -w "This is a string that does not work as it is too long"
[ "$status" -ne 0 ]
}
@test "basic string search replace" {
run ./stringfun -x "This is a bad test" bad great
[ "$output" = "Buffer: [This is a great test..............................]" ] ||
[ "$output" = "Not Implemented!" ]
}
@test "search replace not found" {
run ./stringfun -x "This is a a long string for testing" bad great
[ "$status" -ne 0 ] ||
[ "$output" = "Not Implemented!" ]
}
@test "basic overflow search replace" {
run ./stringfun -x "This is a super long string for testing my program" testing validating
[ "$output" = "Buffer: [This is a super long string for validating my prog]" ] ||
[ "$output" = "Not Implemented!" ]
}
@test "test overflow string replace" {
run ./stringfun -x "This is a super long string for testing my program" testing validating
[ "$output" = "Buffer: [This is a super long string for validating my prog]" ] ||
[ "$output" = "Not Implemented!" ]
}
@test "test shorter string replace" {
run ./stringfun -x "This is a super long string for testing my program" program app
[ "$output" = "Buffer: [This is a super long string for testing my app....]" ] ||
[ "$output" = "Not Implemented!" ]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment