diff --git a/src/complete.cpp b/src/complete.cpp index 6abfe0d81..f0c546323 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1172,7 +1172,7 @@ bool completer_t::try_complete_variable(const wcstring &str) { /// Try to complete the specified string as a username. This is used by ~USER type expansion. /// -/// \return 0 if unable to complete, 1 otherwise +/// \return false if unable to complete, true otherwise bool completer_t::try_complete_user(const wcstring &str) { #ifndef HAVE_GETPWENT // The getpwent() function does not exist on Android. A Linux user on Android isn't @@ -1184,48 +1184,43 @@ bool completer_t::try_complete_user(const wcstring &str) { const wchar_t *cmd = str.c_str(); const wchar_t *first_char = cmd; - if (*first_char != L'~' || wcschr(first_char, L'/')) { - return false; - } + if (*first_char != L'~' || wcschr(first_char, L'/')) return false; const wchar_t *user_name = first_char + 1; const wchar_t *name_end = wcschr(user_name, L'~'); - if (name_end) { - return false; - } + if (name_end) return false; double start_time = timef(); bool result = false; - struct passwd *pw; size_t name_len = wcslen(user_name); + // We don't bother with the thread-safe `getpwent_r()` variant because it isn't needed. This is + // only run in a completion context and thus will only be called from a single thread and there + // is no place else in fish where we call `getpwent()`. + struct passwd *pw; setpwent(); - while ((pw = getpwent()) != 0) { - double current_time = timef(); - if (current_time - start_time > 0.2) { - return 1; - } - - if (!pw->pw_name) { - continue; - } - + // cppcheck-suppress getpwentCalled + while ((pw = getpwent()) != NULL) { const wcstring pw_name_str = str2wcstring(pw->pw_name); const wchar_t *pw_name = pw_name_str.c_str(); if (wcsncmp(user_name, pw_name, name_len) == 0) { wcstring desc = format_string(COMPLETE_USER_DESC, pw_name); append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE); - result = true; + break; } else if (wcsncasecmp(user_name, pw_name, name_len) == 0) { wcstring name = format_string(L"~%ls", pw_name); wcstring desc = format_string(COMPLETE_USER_DESC, pw_name); - append_completion(&this->completions, name, desc, COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE); result = true; + break; } + + // If we've spent too much time (more than 200 ms) doing this give up. + if (timef() - start_time > 0.2) break; } + endpwent(); return result; #endif