static unsigned char complete(EditLine *el, int ch) { DIR *dd = opendir("."); struct dirent *dp; const wchar_t *ptr; char *buf, *bptr; const LineInfoW *lf = el_wline(el); int len, mblen, i; unsigned char res = 0; wchar_t dir[1024]; /* Find the last word */ for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr) continue; len = lf->cursor - ++ptr; /* Convert last word to multibyte encoding, so we can compare to it */ wctomb(NULL, 0); /* Reset shift state */ mblen = MB_LEN_MAX * len + 1; buf = bptr = malloc(mblen); if (buf == NULL) err(1, "malloc"); for (i = 0; i < len; ++i) { /* Note: really should test for -1 return from wctomb */ bptr += wctomb(bptr, ptr[i]); } *bptr = 0; /* Terminate multibyte string */ mblen = bptr - buf; /* Scan directory for matching name */ for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) { if (mblen > strlen(dp->d_name)) continue; if (strncmp(dp->d_name, buf, mblen) == 0) { mbstowcs(dir, &dp->d_name[mblen], sizeof(dir) / sizeof(*dir)); if (el_winsertstr(el, dir) == -1) res = CC_ERROR; else res = CC_REFRESH; break; } } closedir(dd); free(buf); return res; }
/* * Complete the word at or before point, * 'what_to_do' says what to do with the completion. * \t means do standard completion. * `?' means list the possible completions. * `*' means insert all of the possible completions. * `!' means to do standard completion, and list all possible completions if * there is more than one. * * Note: '*' support is not implemented * '!' could never be invoked */ int fn_complete(EditLine *el, char *(*complet_func)(const char *, int), char **(*attempted_completion_function)(const char *, int, int), const wchar_t *word_break, const wchar_t *special_prefixes, const char *(*app_func)(const char *), size_t query_items, int *completion_type, int *over, int *point, int *end) { const LineInfoW *li; wchar_t *temp; char **matches; const wchar_t *ctemp; size_t len; int what_to_do = '\t'; int retval = CC_NORM; if (el->el_state.lastcmd == el->el_state.thiscmd) what_to_do = '?'; /* readline's rl_complete() has to be told what we did... */ if (completion_type != NULL) *completion_type = what_to_do; if (!complet_func) complet_func = fn_filename_completion_function; if (!app_func) app_func = append_char_function; /* We now look backwards for the start of a filename/variable word */ li = el_wline(el); ctemp = li->cursor; while (ctemp > li->buffer && !wcschr(word_break, ctemp[-1]) && (!special_prefixes || !wcschr(special_prefixes, ctemp[-1]) ) ) ctemp--; len = (size_t)(li->cursor - ctemp); temp = el_malloc((len + 1) * sizeof(*temp)); (void)wcsncpy(temp, ctemp, len); temp[len] = '\0'; /* these can be used by function called in completion_matches() */ /* or (*attempted_completion_function)() */ if (point != NULL) *point = (int)(li->cursor - li->buffer); if (end != NULL) *end = (int)(li->lastchar - li->buffer); if (attempted_completion_function) { int cur_off = (int)(li->cursor - li->buffer); matches = (*attempted_completion_function)( ct_encode_string(temp, &el->el_scratch), cur_off - (int)len, cur_off); } else matches = NULL; if (!attempted_completion_function || (over != NULL && !*over && !matches)) matches = completion_matches( ct_encode_string(temp, &el->el_scratch), complet_func); if (over != NULL) *over = 0; if (matches) { int i; size_t matches_num, maxlen, match_len, match_display=1; retval = CC_REFRESH; /* * Only replace the completed string with common part of * possible matches if there is possible completion. */ if (matches[0][0] != '\0') { el_deletestr(el, (int) len); el_winsertstr(el, ct_decode_string(matches[0], &el->el_scratch)); } if (matches[2] == NULL && (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) { /* * We found exact match. Add a space after * it, unless we do filename completion and the * object is a directory. */ el_winsertstr(el, ct_decode_string((*app_func)(matches[0]), &el->el_scratch)); } else if (what_to_do == '!' || what_to_do == '?') { /* * More than one match and requested to list possible * matches. */ for(i = 1, maxlen = 0; matches[i]; i++) { match_len = strlen(matches[i]); if (match_len > maxlen) maxlen = match_len; } /* matches[1] through matches[i-1] are available */ matches_num = (size_t)(i - 1); /* newline to get on next line from command line */ (void)fprintf(el->el_outfile, "\n"); /* * If there are too many items, ask user for display * confirmation. */ if (matches_num > query_items) { (void)fprintf(el->el_outfile, "Display all %zu possibilities? (y or n) ", matches_num); (void)fflush(el->el_outfile); if (getc(stdin) != 'y') match_display = 0; (void)fprintf(el->el_outfile, "\n"); } if (match_display) { /* * Interface of this function requires the * strings be matches[1..num-1] for compat. * We have matches_num strings not counting * the prefix in matches[0], so we need to * add 1 to matches_num for the call. */ fn_display_match_list(el, matches, matches_num+1, maxlen); } retval = CC_REDISPLAY; } else if (matches[0][0]) { /* * There was some common match, but the name was * not complete enough. Next tab will print possible * completions. */ el_beep(el); } else { /* lcd is not a valid object - further specification */ /* is needed */ el_beep(el); retval = CC_NORM; } /* free elements of array and the array itself */ for (i = 0; matches[i]; i++) el_free(matches[i]); el_free(matches); matches = NULL; } el_free(temp); return retval; }