Hi all!
now I added two printf calls to strSubstr and allSubstr to trace where str
and lstr are getting wrong values.
I also added one if statement to check if adding step to str would result in
it going beyond str+lstr. that is :-
if (((orig_str + orig_lstr) - str) <= step) break;
below is full code and run in gdb with still seg fault. suddenly lstr is
getting i can see, but which statement is doing that i can't see
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
size_t strLength(char *cstr) {
size_t index = 0;
while (cstr[index] != '\0') ++index;
return index;
}
char *strFirstCh(char *str, char ch, size_t lstr) {
char *chpos = 0;
size_t current;
for (current = 0; current < lstr; current++) {
if (str[current] == ch) {
chpos = str + current;
break;
}
}
return chpos;
}
int strComp(char *s, char *t, size_t len) {
int ret = 0;
size_t index;
for (index = 0; index < len; index++) {
if (s[index] != t[index]) {
ret = 1;
break;
}
}
return ret;
}
char *strSubstr(
char *str,
char *sub,
size_t lstr,
size_t lsub) {
char *substr = 0;
char *anchor = str;
size_t remaining_len = (lstr - lsub) + 1;
assert(str && sub && lstr && lsub && lstr >= lsub);
printf("in strSubstr: str = %p\tlstr = %zu\n", (void*)str, lstr);
while (remaining_len > 0 && anchor) {
if (anchor = strFirstCh(anchor, *sub, remaining_len)) {
if (strComp(anchor, sub, lsub) == 0) {
substr = anchor;
break;
}
anchor++;
remaining_len--;
}
}
return substr;
}
unsigned allSubstr(
char *str,
char *sub,
size_t lstr,
size_t lsub,
char ***ps,
int overlap) {
unsigned occurs = 0;
unsigned ctr;
char *orig_str = str;
size_t orig_lstr = lstr;
size_t step;
if (overlap == 1)
step = 1;
else
step = lsub;
while (lstr >= lsub) {
str = strSubstr(str, sub, lstr, lsub);
if (str == 0)
break;
occurs++;
if (((orig_str + orig_lstr) - str) <= step) break;
str += step;
lstr = (orig_str + orig_lstr) - str;
printf("in allSubstr: str = %p\tlstr = %zu\n", (void*)str, lstr);
}
if (occurs > 0 && ps) {
str = orig_str;
lstr = orig_lstr;
*ps = malloc(occurs * sizeof **ps);
if (*ps) {
for (ctr = 0; ctr < occurs; ctr++) {
ps[0][ctr] = str = strSubstr(str, sub, lstr, lsub);
str += step;
lstr = (orig_str + orig_lstr) - str;
}
}
}
return occurs;
}
char *replace(char *str, char *substr, char *rep) {
char *new = 0;
size_t lstr, lsubstr, lrep, lnew, strc, newc, repc, replaced;
unsigned replacements;
char **subpos;
assert(str && substr && rep);
lstr = strLength(str);
lsubstr = strLength(substr);
lrep = strLength(rep);
if (lstr == 0 || lsubstr == 0 || lsubstr > lstr)
return 0;
replacements = allSubstr(str, substr, lstr, lsubstr, &subpos, 0);
if (replacements > 0) {
lnew = (lstr - (replacements * lsubstr)) + (replacements * lrep);
new = malloc(lnew + 1);
if (!new) {
free(subpos);
return 0;
}
strc = newc = replaced = 0;
while (strc <= lstr) {
if (replaced < replacements && str + strc == subpos[replaced]) {
for (repc = 0; repc < lrep; repc++) {
new[newc] = rep[repc];
newc++;
}
replaced++;
strc += lsubstr;
}
else {
new[newc] = str[strc];
strc++;
newc++;
}
}
free(subpos);
}
else {
new = malloc(lstr + 1);
if (!new)
return 0;
for (strc = 0; strc <= lstr; strc++)
new[strc] = str[strc];
}
return new;
}
int main(int argc, char **argv) {
char *newstr;
assert(argc == 4);
newstr = replace(argv[1], argv[2], argv[3]);
if (newstr)
printf("%s\n", newstr);
else
printf("replace() -> null\n");
free(newstr);
return 0;
}
# gdb ./replace
(gdb) run "asdkhfaklsdjfhakldfhaklsdjfhakldfhakldfhaskldfh" "asd" "+"
Starting program: /home/fedora/c/replace
"asdkhfaklsdjfhakldfhaklsdjfhakldfhakldfhaskldfh" "asd" "+"
in strSubstr: str = 0x7fff646a86e4 lstr = 47
in allSubstr: str = 0x7fff646a86e7 lstr = 44
in strSubstr: str = 0x7fff646a86e7 lstr = 44
in allSubstr: str = 0x7fff646a8717 lstr = 18446744073709551612
in strSubstr: str = 0x7fff646a8717 lstr = 18446744073709551612
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400698 in strFirstCh (str=0x7fff646a8ff5 "ce", ch=97 'a',
lstr=18446744073709551559) at replace.c:17
17 if (str[current] == ch) {
(gdb) run "asdkhfaklsdjfhakldfhaklsdjfhakldfhakldfhaskldfh" "as" "+"
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fedora/c/replace
"asdkhfaklsdjfhakldfhaklsdjfhakldfhakldfhaskldfh" "as" "+"
in strSubstr: str = 0x7fff27e376e5 lstr = 47
in allSubstr: str = 0x7fff27e376e7 lstr = 45
in strSubstr: str = 0x7fff27e376e7 lstr = 45
in allSubstr: str = 0x7fff27e3770f lstr = 5
in strSubstr: str = 0x7fff27e3770f lstr = 5
in strSubstr: str = 0x7fff27e376e5 lstr = 47
in strSubstr: str = 0x7fff27e376e7 lstr = 45
+dkhfaklsdjfhakldfhaklsdjfhakldfhakldfh+kldfh
Program exited normally.
as its shown using "as" for sub-string instead of "asd" makes it work ok.
somewhere some length calculation is getting wrapped around but am not able
to pin point...
thanks all.