As @TedLyngmo and @robertklep pointed in their comments, the string returned by getenv()
function shouldn't be changed by the application. So, the problem was solved by just copying the returned string into a new string and tokenizing the new one, leaving the original string untouched.
Here is the new working code refactored as @xing suggested in his answer to keep parsing and searching logic separated.
bool tokenize(char *str, char tokens[][100], int max_tokens, int *count, const char *delimiter) {
char *token;
int num_tokens = 0;
token = strtok(str, delimiter);
if (!token)
return false;
strcpy(tokens[0], token);
num_tokens++;
for (int i = 1; token && i < max_tokens; i++) {
token = strtok(NULL, delimiter);
if(token) {
strcpy(tokens[i], token);
num_tokens++;
}
}
*count = num_tokens;
return true;
}
bool str_in_path(char *target, char *result) {
const char *path = getenv("PATH");
char path_copy[strlen(path)];
strcpy(path_copy, path); // copying the path to avoid manipulating the original string returned by getenv()
char dirs[20][100] = {};
int num_dirs;
tokenize(path_copy, dirs, 20, &num_dirs, ":"); // tokenizing the copied path instead of the original one.
for (int i = 0; i < num_dirs; i++) {
struct dirent *entry = NULL;
DIR *dir = opendir(dirs[i]);
if (dir == NULL) {
fprintf(stderr, "can't open directory %s\n", dirs[i]);
continue;
}
while ((entry = readdir(dir)) != NULL) {
if (!strcmp(target, entry->d_name)) {
strcpy(result, dirs[i]);
strcat(result, "/");
strcat(result, entry->d_name);
closedir(dir);
return true;
}
}
closedir(dir);
}
return false;
}