diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1fac8f87447f5..7842c16277e20 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -127,15 +127,40 @@ proc expandTilde*(path: string): string {. assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" assert expandTilde("/foo/bar") == "/foo/bar" + template tryGetHomeOrRet = + result = getHomeDir() + if result == "": + result = path + return + if len(path) == 0 or path[0] != '~': result = path elif len(path) == 1: - result = getHomeDir() + tryGetHomeOrRet elif (path[1] in {DirSep, AltSep}): - result = getHomeDir() / path.substr(2) + tryGetHomeOrRet + result = result / path.substr(2) else: - # TODO: handle `~bob` and `~bob/` which means home of bob - result = path + when compiles(getHomeDir("bob")): + # handle path beginning with `~bob` and `~bob/` + # which means home of bob + var i = path.find(DirSep, 1) + if i < 0: + i = len(path) + + let + name = path[1.. int.high shr 1: + nomem = true + break + + bufsize = bufsize shl 1 + defer: deallocShared buf + else: + p = getpwnam(name_chars) + + if p.isNil: + if nomem: + raise newException(OutOfMemDefect, "") + #else: ...KeyError "getpwnam(): name not found: " & username.repr + # XXX: do not raise KeyError, as it used to raise no CatchableError. + # e.g. `osproc.findExe(data.sysCommand, true, ExeExts)` expects so + else: + result = "" + if not getPwDir(p, result): + return + + proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the home directory of the current user. + ## + ## Returns an empty string if failed to get an valid result ## ## This proc is wrapped by the `expandTilde proc`_ ## for the convenience of processing paths coming from user configuration files. @@ -22,8 +99,22 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", import std/os assert getHomeDir() == expandTilde("~") - when defined(windows): return getEnv("USERPROFILE") & "\\" - else: return getEnv("HOME") & "/" + template ret(res) = + result = res + if result != "": + result.add DirSep + return + when defined(windows): ret getEnv("USERPROFILE") + elif declared(getpwuid): + if existsEnv("HOME"): + ret getEnv("HOME") + let pwd = getpwuid(getuid()) + if pwd.isNil: + return + let cstr = pwd.pw_dir + if cstr.isNil: return + ret $cstr + else: ret getEnv("HOME") proc getDataDir*(): string {.rtl, extern: "nos$1" tags: [ReadEnvEffect, ReadIOEffect].} =