lint: deal with getpwent() warnings

This suppresses lint warnings about using `getpwent()` because there is
only one context where fish uses it. Thus the fact it may not be thread
safe is not relevant to fish. This also improves that call site in
`completer_t::try_complete_user()` method by short-circuiting the loop
when a match is found.
This commit is contained in:
Kurtis Rader 2017-05-10 22:07:01 -07:00
parent f10e4f88b6
commit c114cbc9af

View file

@ -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. /// 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) { bool completer_t::try_complete_user(const wcstring &str) {
#ifndef HAVE_GETPWENT #ifndef HAVE_GETPWENT
// The getpwent() function does not exist on Android. A Linux user on Android isn't // 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 *cmd = str.c_str();
const wchar_t *first_char = cmd; const wchar_t *first_char = cmd;
if (*first_char != L'~' || wcschr(first_char, L'/')) { if (*first_char != L'~' || wcschr(first_char, L'/')) return false;
return false;
}
const wchar_t *user_name = first_char + 1; const wchar_t *user_name = first_char + 1;
const wchar_t *name_end = wcschr(user_name, L'~'); const wchar_t *name_end = wcschr(user_name, L'~');
if (name_end) { if (name_end) return false;
return false;
}
double start_time = timef(); double start_time = timef();
bool result = false; bool result = false;
struct passwd *pw;
size_t name_len = wcslen(user_name); 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(); setpwent();
while ((pw = getpwent()) != 0) { // cppcheck-suppress getpwentCalled
double current_time = timef(); while ((pw = getpwent()) != NULL) {
if (current_time - start_time > 0.2) {
return 1;
}
if (!pw->pw_name) {
continue;
}
const wcstring pw_name_str = str2wcstring(pw->pw_name); const wcstring pw_name_str = str2wcstring(pw->pw_name);
const wchar_t *pw_name = pw_name_str.c_str(); const wchar_t *pw_name = pw_name_str.c_str();
if (wcsncmp(user_name, pw_name, name_len) == 0) { if (wcsncmp(user_name, pw_name, name_len) == 0) {
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name); wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE); append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE);
result = true; result = true;
break;
} else if (wcsncasecmp(user_name, pw_name, name_len) == 0) { } else if (wcsncasecmp(user_name, pw_name, name_len) == 0) {
wcstring name = format_string(L"~%ls", pw_name); wcstring name = format_string(L"~%ls", pw_name);
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name); wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, name, desc, append_completion(&this->completions, name, desc,
COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE); COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE);
result = true; 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(); endpwent();
return result; return result;
#endif #endif