Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
CS283
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
dtt47
CS283
Commits
8f0864a2
Commit
8f0864a2
authored
6 months ago
by
dtt47
Browse files
Options
Downloads
Patches
Plain Diff
update a1
parent
3b926323
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
stringfun.c
+424
-0
424 additions, 0 deletions
stringfun.c
with
424 additions
and
0 deletions
stringfun.c
0 → 100644
+
424
−
0
View file @
8f0864a2
#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
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment