+ /* Do TAB completion */
+ static int num_matches;
+ static char **matches;
+
+ if (lastWasTab == 0) { /* free all memory */
+ if (matches) {
+ while (num_matches > 0)
+ free(matches[--num_matches]);
+ free(matches);
+ matches = (char **) NULL;
+ }
+ return;
+ }
+ if (! *lastWasTab) {
+
+ char *tmp;
+ 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)
+ matches = username_tab_completion(matchBuf, &num_matches);
+#endif
+ /* Try to match any executable in our path and everything
+ * in the current working directory that matches. */
+ if (!matches)
+ matches =
+ exe_n_cwd_tab_completion(matchBuf,
+ &num_matches, find_type);
+ /* Remove duplicate found */
+ if(matches) {
+ int i, j;
+ /* bubble */
+ for(i=0; i<(num_matches-1); i++)
+ for(j=i+1; j<num_matches; j++)
+ if(matches[i]!=0 && matches[j]!=0 &&
+ strcmp(matches[i], matches[j])==0) {
+ free(matches[j]);
+ matches[j]=0;
+ }
+ j=num_matches;
+ num_matches = 0;
+ for(i=0; i<j; i++)
+ if(matches[i]) {
+ if(!strcmp(matches[i], "./"))
+ matches[i][1]=0;
+ else if(!strcmp(matches[i], "../"))
+ matches[i][2]=0;
+ matches[num_matches++]=matches[i];
+ }
+ }
+ /* Did we find exactly one match? */
+ if (!matches || num_matches > 1) {
+ char *tmp1;
+
+ beep();
+ if (!matches)
+ return; /* not found */
+ /* sort */
+ qsort(matches, num_matches, sizeof(char *), match_compare);
+
+ /* find minimal match */
+ tmp = bb_xstrdup(matches[0]);
+ for (tmp1 = tmp; *tmp1; tmp1++)
+ for (len_found = 1; len_found < num_matches; len_found++)
+ if (matches[len_found][(tmp1 - tmp)] != *tmp1) {
+ *tmp1 = 0;
+ break;
+ }
+ if (*tmp == 0) { /* have unique */
+ free(tmp);
+ return;
+ }
+ } else { /* one match */
+ tmp = matches[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);
+ }
+ if (tmp != matches[0])
+ 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(matches, num_matches);
+ redraw(0, len - sav_cursor);
+ }
+ }