diff --git a/libc/src/pwd.cpp b/libc/src/pwd.cpp index d39990f4..33c1eaf5 100644 --- a/libc/src/pwd.cpp +++ b/libc/src/pwd.cpp @@ -7,6 +7,36 @@ static struct passwd pwd; static FILE* f { nullptr }; static char buf[4096]; +// Variant of strtok that returns empty tokens when there are several delimiters, instead of skipping all at once. +// Example: +// strtok("hello:world::!:", ":") -> "hello", "world", "!" +// _strtok_once("hello:world::!:", ":") -> "hello", "world", "", "!" +static char* _strtok_once(char* str, const char* delim) +{ + static char* s = nullptr; + if (str) s = str; + if (!s) return nullptr; + + if (*s) + { + if (*s == 0) return nullptr; + + size_t use = strcspn(s, delim); + char* result = s; + + if (s[use] != 0) + { + s[use] = 0; + s += (use + 1); + } + else { s = nullptr; } + + return result; + } + + return nullptr; +} + extern "C" { struct passwd* getpwent() @@ -22,25 +52,25 @@ extern "C" char* rc = fgets(buf, sizeof(buf), f); if (!rc) return nullptr; - char* name = strtok(rc, ":\n"); + char* name = _strtok_once(rc, ":\n"); if (!name) continue; - char* passwd = strtok(nullptr, ":\n"); + char* passwd = _strtok_once(nullptr, ":\n"); if (!passwd) continue; - char* uid = strtok(nullptr, ":\n"); + char* uid = _strtok_once(nullptr, ":\n"); if (!uid) continue; - char* gid = strtok(nullptr, ":\n"); + char* gid = _strtok_once(nullptr, ":\n"); if (!gid) continue; - char* gecos = strtok(nullptr, ":\n"); + char* gecos = _strtok_once(nullptr, ":\n"); if (!gecos) continue; - char* dir = strtok(nullptr, ":\n"); + char* dir = _strtok_once(nullptr, ":\n"); if (!dir) continue; - char* shell = strtok(nullptr, ":\n"); + char* shell = _strtok_once(nullptr, ":\n"); if (!shell) continue; pwd.pw_name = name;