char *filename_completion_function(const char *text, int state) {
printf("\n[COMP] Entering: text='%s', state=%d, last_state=%d\n",
text, state, comp_state.last_state);
// 拦截只敲 Tab 的情况
if (text == NULL || *text == '\0') {
printf("用户未输入任何文本,只敲 Tab,不提供补全\n");
return NULL;
}
char current_dir[PATH_MAX];
char abs_path[PATH_MAX];
int reset_completion = 0;
// <<< 新增字段,用于判断是否是 flash:/ 模式
int is_flash_mode = (strncmp(text, "flash:/", 7) == 0);
int is_f_prefix = (strncmp(text, "f", 1) == 0 && strncmp(text, "flash:/", 7) != 0);
// 初始化新补全
if (state == 0) {
printf(" Starting new completion\n");
// 获取当前工作目录
getcwd(current_dir, sizeof(current_dir));
snprintf(abs_path, sizeof(abs_path), "%s/%s", current_dir, text);
if (access(abs_path, F_OK) != 0) {
reset_completion = 1;
}
printf("\n111filename_completion_function: reset_completion = %d, abs_path = '%s'\n", reset_completion, abs_path);
char *tmp_base = NULL;
char *tmp_prefix = NULL;
int tmp_level = 0;
parse_input_text(text, &tmp_base, &tmp_prefix, &tmp_level);
printf("\n222filename_completion_function: text = '%s', tmp_base = '%s', tmp_prefix = '%s'\n",
text, tmp_base, tmp_prefix);
int same_reset = 0;
struct stat st_tmp;
char tmp_path[PATH_MAX];
if (comp_state.matches && comp_state.matches[0]) {
for (int i = 0; comp_state.matches[i]; i++) {
printf("\n333filename_completion_function: comp_state.matches[%d] = '%s'\n", i, comp_state.matches[i]);
if (strncmp(comp_state.matches[i], tmp_prefix, strlen(tmp_prefix)) == 0) {
snprintf(tmp_path, sizeof(tmp_path), "%s/%s%s", current_dir, tmp_base, comp_state.matches[i]);
printf("\n444filename_completion_function: tmp_path = '%s', current_dir = '%s', comp_state.matches[%d] = '%s'\n",
tmp_path, current_dir, i, comp_state.matches[i]);
if (stat(tmp_path, &st_tmp) == 0 && S_ISDIR(st_tmp.st_mode)) {
same_reset = 1;
printf("\nfilename_completion_function: same_reset = %d\n", same_reset);
break;
}
}
}
}
printf("\n555filename_completion_function: current_dir = '%s', text = '%s', abs_path = '%s', reset_completion = %d, same_reset = %d\n",
current_dir, text, abs_path, reset_completion, same_reset);
printf("\n666filename_completion_function: 11111111 comp_state.persistent_path = '%s'\n", comp_state.persistent_path);
int same_context = is_same_completion_context(text);
printf(" Same context: %d\n", same_context);
if ((!same_context) || (reset_completion && same_reset) || (!comp_state.persistent_path || comp_state.persistent_path[0] == '\0')) {
reset_completion_state();
printf("\n -----------------common reset---------------\n");
char *current_base = NULL;
char *current_prefix = NULL;
int current_level = 0;
parse_input_text(text, ¤t_base, ¤t_prefix, ¤t_level);
printf("\n777filename_completion_function: current_base = '%s', current_prefix = '%s', current_level = %d\n",
current_base, current_prefix, current_level);
comp_state.base_dir = current_base;
comp_state.current_text = XSTRDUP(MTYPE_TMP, text);
comp_state.original_prefix = XSTRDUP(MTYPE_TMP, current_prefix);
comp_state.current_level = current_level;
comp_state.max_level = current_level + 3;
// 检查是否用户已经明确进入了子目录
int ends_with_slash = text[strlen(text) - 1] == '/';
if (ends_with_slash) {
comp_state.persistent_path = XSTRDUP(MTYPE_TMP, text);
comp_state.max_level = current_level + 3;
} else {
comp_state.persistent_path = XSTRDUP(MTYPE_TMP, current_base);
comp_state.max_level = current_level;
}
// 生成当前目录的补全项
// <<< 第一次调用:根据输入前缀生成匹配项
if (is_flash_mode) {
// <<< flash:/ 开头,直接扫描 /mnt/switch/ 路径
comp_state.matches = generate_current_dir_paths("/mnt/switch/", text + 7, current_level == 0);
comp_state.flash_mode = 1;
} else if (is_f_prefix) {
// <<< f 开头,先扫描当前目录
comp_state.matches = generate_current_dir_paths(current_base, current_prefix, current_level == 0);
if (comp_state.matches == NULL || comp_state.matches[0] == NULL) {
// <<< 当前目录没有 f 开头的,自动切换到 flash:/ 路径
comp_state.base_dir = XSTRDUP(MTYPE_TMP, "flash:/");
comp_state.matches = generate_current_dir_paths("/mnt/switch/", text, current_level == 0);
comp_state.flash_mode = 1;
} else {
// <<< 有本地 f 开头项,追加 flash:/ 虚拟项
int count = 0;
while (comp_state.matches[count]) count++;
// 防止重复加入
int flash_already_in_list = 0;
for (int i = 0; comp_state.matches[i]; i++) {
if (strncmp(comp_state.matches[i], "flash:/", 7) == 0) {
flash_already_in_list = 1;
break;
}
}
if (!flash_already_in_list && count < 1024 - 1) {
char **temp = (char **)XREALLOC(MTYPE_TMP, comp_state.matches, (count + 3) * sizeof(char*));
comp_state.matches = temp;
comp_state.matches[count] = XSTRDUP(MTYPE_TMP, "flash:/");
comp_state.matches[count + 1] = XSTRDUP(MTYPE_TMP, "");
comp_state.matches[count + 2] = NULL;
//count++;
//comp_state.count = count;
if (comp_state.matches && comp_state.matches[0]) {
printf("\n flash: comp_state.matches = ");
for (int i = 0; comp_state.matches[i]; i++) {
printf("%s, ", comp_state.matches[i]);
}
printf("\n");
}
}
}
} else {
// <<< 非 f 开头,正常路径补全
comp_state.matches = generate_current_dir_paths(current_base, current_prefix, current_level == 0);
}
comp_state.count = 0;
if (comp_state.matches) {
while (comp_state.matches[comp_state.count]) {
comp_state.count++;
}
printf(" Generated %d matches\n", comp_state.count);
} else {
comp_state.count = 0;
}
comp_state.last_state = -1; // 重置索引
}
}
printf("\n888filename_completion_function: comp_state.base_dir = '%s', comp_state.current_text = '%s', comp_state.original_prefix = '%s', comp_state.persistent_path = '%s'\n",
comp_state.base_dir, comp_state.current_text, comp_state.original_prefix, comp_state.persistent_path);
// 没有匹配项
if (!comp_state.matches || comp_state.count == 0) {
printf("[COMP] No matches found\n");
return NULL;
}
// 获取下一个匹配项
int next_index = (comp_state.last_state + 1) % comp_state.count;
comp_state.last_state = next_index;
char *match = comp_state.matches[next_index];
// 构建完整路径
char *full_path = NULL;
if (strncmp(match, "flash:/", 7) == 0) {
// <<< 返回 flash:/ 项
full_path = XSTRDUP(MTYPE_TMP, match);
} else if (comp_state.flash_mode) {
// <<< flash:/ 模式,构建 flash:/xxx/yyy 格式
full_path = XCALLOC(MTYPE_TMP, strlen("flash:/") + strlen(match) + 2);
snprintf(full_path, strlen("flash:/") + strlen(match) + 2, "flash:/%s", match);
} else {
// 通用路径拼接逻辑
if (comp_state.base_dir && strlen(comp_state.base_dir) > 0) {
int base_len = strlen(comp_state.base_dir);
int needs_slash = base_len > 0 && comp_state.base_dir[base_len - 1] != '/';
full_path = XCALLOC(MTYPE_TMP, strlen(match) + base_len + 2);
if (needs_slash) {
snprintf(full_path, strlen(match) + base_len + 2, "%s/%s", comp_state.base_dir, match);
} else {
snprintf(full_path, strlen(match) + base_len + 2, "%s%s", comp_state.base_dir, match);
}
} else {
full_path = XSTRDUP(MTYPE_TMP, match);
}
}
printf("[COMP] Returning: '%s'\n", full_path);
return full_path;
}
<dahua>dir
dir: argv[0] = '(null)', argv[1] = '(null)'
Directory of flash:
0 drw- - Jan 01 1970 00:04:56 cfg
1 drw- - Jan 01 1970 00:00:54 etc
2 drw- - Jan 01 1970 02:54:15 fa
3 -rw- 2418 Jan 01 1970 00:02:47 fb.txt
4 drw- - Jan 01 1970 00:01:26 home
5 drw- - Jan 01 1970 00:15:14 installers
6 drw- - Jan 01 1970 00:04:55 logfile
436148 KB total (340564 KB free)
<dahua>
<dahua>dir f
【cmlsh_completion】text = f
[MATCHES] Called with text='f'
[COMP] Entering: text='f', state=0, last_state=-1
Starting new completion
111filename_completion_function: reset_completion = 1, abs_path = '/mnt/switch/f'
222filename_completion_function: text = 'f', tmp_base = '', tmp_prefix = 'f'
555filename_completion_function: current_dir = '/mnt/switch', text = 'f', abs_path = '/mnt/switch/f', reset_completion = 1, same_reset = 0
666filename_completion_function: 11111111 comp_state.persistent_path = '(null)'
Same context: 0
-----------------common reset---------------
777filename_completion_function: current_base = '', current_prefix = 'f', current_level = 0
[generate] Scanning directory: '.' with prefix: 'f'
跳过软链接: main_uImage
[generate] Found 2 matches.
generate_current_dir_paths: matches = fa/, fb.txt,
flash: comp_state.matches = fa/, fb.txt, flash:/, ,
Generated 4 matches
888filename_completion_function: comp_state.base_dir = '', comp_state.current_text = 'f', comp_state.original_prefix = 'f', comp_state.persistent_path = ''
[COMP] Returning: 'fa/'
[MATCHES] Returning single match: 'fa/'
a/
【cmlsh_completion】text = fa/
[MATCHES] Called with text='fa/'
[COMP] Entering: text='fa/', state=0, last_state=0
Starting new completion
111filename_completion_function: reset_completion = 0, abs_path = '/mnt/switch/fa/'
222filename_completion_function: text = 'fa/', tmp_base = 'fa/', tmp_prefix = ''
333
Username:
分析一下打印,为什么会有异常退出?
最新发布