我正在尝试编写一个函数来在 PATH 目录中搜索。我使用
getenv("PATH")
获取路径字符串,然后使用 strtok()
分割它。
第二次调用函数时,它不会重新初始化路径字符串。它仅在路径的第一部分搜索。
我知道
strtok()
修改了以 \0
终止每个标记的原始字符串。但就我而言,我不明白为什么再次调用该函数不会创建带有正常分隔符“:”的新字符串。
这是我的代码:
bool str_in_path(char *target, char *result) {
char *path = getenv("PATH");
char *token;
char tokens[10][100];
int count = 0;
token = strtok(path, ":");
strcpy(tokens[0], token);
count++;
for (int i = 1; token && i < 10; i++) {
token = strtok(NULL, delimiter);
if (token) {
strcpy(tokens[i], token);
count++;
}
}
for (int i = 0; i < count; i++) {
struct dirent *entry = NULL
DIR *dir = opendir(tokens[i]);
if (dir == NULL) {
fprintf(stderr, "can't open directory %s\n", tokens[i]);
continue;
}
while ((entry = readdir(dir)) != NULL) {
if (!strcmp(target, entry->d_name)) {
strcpy(result, tokens[i]);
strcat(result, "/");
strcat(result, entry->d_name);
closedir(dir);
return true;
}
}
closedir(dir);
}
return false;
}
我第一次调用该函数时,它的行为符合我的预期。第二次它只搜索路径的第一部分。尽管它调用
char *path = getenv("PATH");
来初始化路径字符串。为什么会这样以及我该如何解决它。
正如@chux的评论中提到的,
strcspn()
可以用于解析而不修改源字符串。#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <dirent.h>
char **parse_path ( char *path, char *delimiter) {
char **tokens = NULL;
char **tmp = NULL;
char *token = path;;
char *end = path;
size_t items = 0;
size_t span = 0;
while ( *token) { // not terminating zero
end += strcspn ( token, delimiter);
if ( end == token) {
break;
}
if ( NULL == ( tmp = realloc ( tokens, sizeof *tokens * (items + 2)))) {
fprintf ( stderr, "problem realloc tokens\n");
break;
}
tokens = tmp;
span = end - token;
if ( NULL == ( tokens[items] = malloc ( span + 1))) {
fprintf ( stderr, "problem malloc token[items]\n");
break;
}
memmove ( tokens[items], token, span);
tokens[items][span] = 0; // zero terminate
// printf ( "\t%s\n", tokens[items]);
++items;
tokens[items] = NULL; // sentenal NULL
if ( *end) { // not terminating zero
++end; // advance past one delimiteer
}
token = end;
}
return tokens;
}
bool str_in_path_tokens ( char **tokens, char *target, char *result) {
while ( tokens && *tokens) {
struct dirent *entry = NULL;
DIR *dir = opendir ( *tokens);
if ( dir == NULL) {
fprintf(stderr, "can't open directory %s\n", *tokens);
continue;
}
while ( ( entry = readdir ( dir)) != NULL) {
if ( ! strcmp ( target, entry->d_name)) {
strcpy(result, *tokens);
strcat(result, "/");
strcat(result, entry->d_name);
closedir(dir);
return true;
}
closedir(dir);
}
++tokens;
}
return false;
}
void show_path_tokens ( char **tokens) {
while ( tokens && *tokens) {
printf ( "%s\n", *tokens);
++tokens;
}
}
void free_path_tokens ( char **tokens) {
while ( tokens && *tokens) {
free ( *tokens);
++tokens;
}
}
int main ( void) {
char *path = getenv ( "PATH");
char **pathtokens = NULL;
printf ( "%s\n", path);
pathtokens = parse_path ( path, ":");
show_path_tokens ( pathtokens);
// call
// str_in_path_tokens ( pathtokens, target, result);
// as needed with various targets and results
// no need to reparse the path
free_path_tokens ( pathtokens);
free ( pathtokens);
}