void f() { if (buf[0] == '~' && strchr(tmp, '/') == NULL) { buf = mallocstrcpy(buf, tmp); matches = username_tab_completion(tmp, &num_matches); } /* If we're in the middle of the original line, copy the string only up to the cursor position into buf, so tab completion will result in buf's containing only the tab-completed path/filename. */ else if (strlen(buf) > strlen(tmp)) buf = mallocstrcpy(buf, tmp); }
/* Do TAB completion */ static void input_tab(int *lastWasTab) { if (!(state->flags & TAB_COMPLETION)) return; if (!*lastWasTab) { char *tmp, *tmp1; int len_found; char matchBuf[MAX_LINELEN]; int find_type; int recalc_pos; *lastWasTab = TRUE; /* flop trigger */ /* Make a local copy of the string -- up * to the position of the cursor */ tmp = strncpy(matchBuf, command_ps, cursor); tmp[cursor] = '\0'; find_type = find_match(matchBuf, &recalc_pos); /* Free up any memory already allocated */ free_tab_completion_data(); #if ENABLE_FEATURE_USERNAME_COMPLETION /* If the word starts with `~' and there is no slash in the word, * then try completing this word as a username. */ if (state->flags & USERNAME_COMPLETION) if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) username_tab_completion(matchBuf, NULL); #endif /* Try to match any executable in our path and everything * in the current working directory */ if (!matches) exe_n_cwd_tab_completion(matchBuf, find_type); /* Sort, then remove any duplicates found */ if (matches) { int i, n = 0; qsort(matches, num_matches, sizeof(char*), match_compare); for (i = 0; i < num_matches - 1; ++i) { if (matches[i] && matches[i+1]) { /* paranoia */ if (strcmp(matches[i], matches[i+1]) == 0) { free(matches[i]); matches[i] = NULL; /* paranoia */ } else { matches[n++] = matches[i]; } } } matches[n] = matches[i]; num_matches = n + 1; } /* Did we find exactly one match? */ if (!matches || num_matches > 1) { beep(); if (!matches) return; /* not found */ /* find minimal match */ // ash: yet another failure in trying to achieve "we don't die on OOM" tmp1 = xstrdup(matches[0]); for (tmp = tmp1; *tmp; tmp++) for (len_found = 1; len_found < num_matches; len_found++) if (matches[len_found][(tmp - tmp1)] != *tmp) { *tmp = '\0'; break; } if (*tmp1 == '\0') { /* have unique */ free(tmp1); return; } tmp = add_quote_for_spec_chars(tmp1); free(tmp1); } else { /* one match */ tmp = add_quote_for_spec_chars(matches[0]); /* for next completion current found */ *lastWasTab = FALSE; len_found = strlen(tmp); if (tmp[len_found-1] != '/') { tmp[len_found] = ' '; tmp[len_found+1] = '\0'; } } len_found = strlen(tmp); /* have space to placed match? */ if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) { /* before word for match */ command_ps[cursor - recalc_pos] = 0; /* save tail line */ strcpy(matchBuf, command_ps + cursor); /* add match */ strcat(command_ps, tmp); /* add tail */ strcat(command_ps, matchBuf); /* back to begin word for match */ input_backward(recalc_pos); /* new pos */ recalc_pos = cursor + len_found; /* new len */ command_len = strlen(command_ps); /* write out the matched command */ redraw(cmdedit_y, command_len - recalc_pos); } free(tmp); } else { /* Ok -- the last char was a TAB. Since they * just hit TAB again, print a list of all the * available choices... */ if (matches && num_matches > 0) { int sav_cursor = cursor; /* change goto_new_line() */ /* Go to the next line */ goto_new_line(); showfiles(); redraw(0, command_len - sav_cursor); } } }
static void exe_n_cwd_tab_completion(char *command, int type) { DIR *dir; struct dirent *next; char dirbuf[BUFSIZ]; struct stat st; char *path1[1]; char **paths = path1; int npaths; int i; char *found; char *pfind = strrchr(command, '/'); path1[0] = "."; if (pfind == NULL) { /* no dir, if flags==EXE_ONLY - get paths, else "." */ npaths = path_parse(&paths, type); pfind = command; } else { /* with dir */ /* save for change */ strcpy(dirbuf, command); /* set dir only */ dirbuf[(pfind - command) + 1] = 0; #ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION if (dirbuf[0] == '~') /* ~/... or ~user/... */ username_tab_completion(dirbuf, dirbuf); #endif /* "strip" dirname in command */ pfind++; paths[0] = dirbuf; npaths = 1; /* only 1 dir */ } for (i = 0; i < npaths; i++) { dir = opendir(paths[i]); if (!dir) /* Don't print an error */ continue; while ((next = readdir(dir)) != NULL) { char *str_found = next->d_name; int add_chr = 0; /* matched ? */ if (strncmp(str_found, pfind, strlen(pfind))) continue; /* not see .name without .match */ if (*str_found == '.' && *pfind == 0) { if (*paths[i] == '/' && paths[i][1] == 0 && str_found[1] == 0) str_found = ""; /* only "/" */ else continue; } found = concat_path_file(paths[i], str_found); /* hmm, remover in progress? */ if (stat(found, &st) < 0) goto cont; /* find with dirs ? */ if (paths[i] != dirbuf) strcpy(found, next->d_name); /* only name */ if (S_ISDIR(st.st_mode)) { /* name is directory */ char *e = found + strlen(found) - 1; add_chr = '/'; if(*e == '/') *e = '\0'; } else { /* not put found file if search only dirs for cd */ if (type == FIND_DIR_ONLY) goto cont; if (type == FIND_FILE_ONLY || (type == FIND_EXE_ONLY && is_execute(&st))) add_chr = ' '; } /* Add it to the list */ add_match(found, add_chr); continue; cont: free(found); } closedir(dir); } if (paths != path1) { free(paths[0]); /* allocated memory only in first member */ free(paths); } }
static void exe_n_cwd_tab_completion(char *command, int type) { DIR *dir; struct dirent *next; char dirbuf[MAX_LINELEN]; struct stat st; char *path1[1]; char **paths = path1; int npaths; int i; char *found; char *pfind = strrchr(command, '/'); npaths = 1; path1[0] = (char*)"."; if (pfind == NULL) { /* no dir, if flags==EXE_ONLY - get paths, else "." */ npaths = path_parse(&paths, type); pfind = command; } else { /* dirbuf = ".../.../.../" */ safe_strncpy(dirbuf, command, (pfind - command) + 2); #if ENABLE_FEATURE_USERNAME_COMPLETION if (dirbuf[0] == '~') /* ~/... or ~user/... */ username_tab_completion(dirbuf, dirbuf); #endif paths[0] = dirbuf; /* point to 'l' in "..../last_component" */ pfind++; } for (i = 0; i < npaths; i++) { dir = opendir(paths[i]); if (!dir) /* Don't print an error */ continue; while ((next = readdir(dir)) != NULL) { int len1; const char *str_found = next->d_name; /* matched? */ if (strncmp(str_found, pfind, strlen(pfind))) continue; /* not see .name without .match */ if (*str_found == '.' && *pfind == 0) { if (NOT_LONE_CHAR(paths[i], '/') || str_found[1]) continue; str_found = ""; /* only "/" */ } found = concat_path_file(paths[i], str_found); /* hmm, remover in progress? */ if (stat(found, &st) < 0) goto cont; /* find with dirs? */ if (paths[i] != dirbuf) strcpy(found, next->d_name); /* only name */ len1 = strlen(found); found = xrealloc(found, len1 + 2); found[len1] = '\0'; found[len1+1] = '\0'; if (S_ISDIR(st.st_mode)) { /* name is directory */ if (found[len1-1] != '/') { found[len1] = '/'; } } else { /* not put found file if search only dirs for cd */ if (type == FIND_DIR_ONLY) goto cont; } /* Add it to the list */ add_match(found); continue; cont: free(found); } closedir(dir); } if (paths != path1) { free(paths[0]); /* allocated memory only in first member */ free(paths); } }
static void input_tab(int *lastWasTab) { /* Do TAB completion */ if (lastWasTab == 0) { /* free all memory */ if (matches) { while (num_matches > 0) free(matches[--num_matches]); free(matches); matches = (char **) NULL; free(add_char_to_match); add_char_to_match = NULL; } return; } if (! *lastWasTab) { char *tmp, *tmp1; int len_found; char matchBuf[BUFSIZ]; int find_type; int recalc_pos; *lastWasTab = TRUE; /* flop trigger */ /* Make a local copy of the string -- up * to the position of the cursor */ tmp = strncpy(matchBuf, command_ps, cursor); tmp[cursor] = 0; find_type = find_match(matchBuf, &recalc_pos); /* Free up any memory already allocated */ input_tab(0); #ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION /* If the word starts with `~' and there is no slash in the word, * then try completing this word as a username. */ if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) username_tab_completion(matchBuf, NULL); if (!matches) #endif /* Try to match any executable in our path and everything * in the current working directory that matches. */ exe_n_cwd_tab_completion(matchBuf, find_type); /* Remove duplicate found and sort */ if(matches) { int i, j, n, srt; /* bubble */ n = num_matches; for(i=0; i<(n-1); i++) for(j=i+1; j<n; j++) if(matches[i]!=NULL && matches[j]!=NULL) { srt = strcmp(matches[i], matches[j]); if(srt == 0) { free(matches[j]); matches[j]=0; } else if(srt > 0) { tmp1 = matches[i]; matches[i] = matches[j]; matches[j] = tmp1; srt = add_char_to_match[i]; add_char_to_match[i] = add_char_to_match[j]; add_char_to_match[j] = srt; } } j = n; n = 0; for(i=0; i<j; i++) if(matches[i]) { matches[n]=matches[i]; add_char_to_match[n]=add_char_to_match[i]; n++; } num_matches = n; } /* Did we find exactly one match? */ if (!matches || num_matches > 1) { beep(); if (!matches) return; /* not found */ /* find minimal match */ tmp1 = bb_xstrdup(matches[0]); for (tmp = tmp1; *tmp; tmp++) for (len_found = 1; len_found < num_matches; len_found++) if (matches[len_found][(tmp - tmp1)] != *tmp) { *tmp = 0; break; } if (*tmp1 == 0) { /* have unique */ free(tmp1); return; } tmp = add_quote_for_spec_chars(tmp1, 0); free(tmp1); } else { /* one match */ tmp = add_quote_for_spec_chars(matches[0], add_char_to_match[0]); /* for next completion current found */ *lastWasTab = FALSE; } len_found = strlen(tmp); /* have space to placed match? */ if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { /* before word for match */ command_ps[cursor - recalc_pos] = 0; /* save tail line */ strcpy(matchBuf, command_ps + cursor); /* add match */ strcat(command_ps, tmp); /* add tail */ strcat(command_ps, matchBuf); /* back to begin word for match */ input_backward(recalc_pos); /* new pos */ recalc_pos = cursor + len_found; /* new len */ len = strlen(command_ps); /* write out the matched command */ redraw(cmdedit_y, len - recalc_pos); } free(tmp); } else { /* Ok -- the last char was a TAB. Since they * just hit TAB again, print a list of all the * available choices... */ if (matches && num_matches > 0) { int sav_cursor = cursor; /* change goto_new_line() */ /* Go to the next line */ goto_new_line(); showfiles(); redraw(0, len - sav_cursor); } } }