get_env for Win32, @pierrec's get_config_dir and get_home_dir

This commit is contained in:
Christoffer Lerno
2023-09-25 16:08:27 +02:00
committed by Christoffer Lerno
parent 2a683a6a05
commit c5404c6573
5 changed files with 124 additions and 22 deletions

View File

@@ -448,6 +448,17 @@ fn void Path.free(self)
free(self.path_string.ptr); free(self.path_string.ptr);
} }
fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.print(self.str_view());
}
fn String Path.to_string(&self, Allocator* using = mem::heap()) @dynamic
{
return self.str_view().copy(using);
}
const bool[256] RESERVED_PATH_CHAR_POSIX = { const bool[256] RESERVED_PATH_CHAR_POSIX = {
[0] = true, [0] = true,
['/'] = true, ['/'] = true,

View File

@@ -430,7 +430,7 @@ macro usz! Stream.write_varint(&self, x)
{ {
var $Type = $typeof(x); var $Type = $typeof(x);
const MAX = MAX_VARS[$Type.sizeof]; const MAX = MAX_VARS[$Type.sizeof];
char[MAX] buffer; char[MAX] buffer @noinit;
usz i; usz i;
while (x >= 0x80) while (x >= 0x80)
{ {

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Copyright (c) 2021-2023 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license // Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file. // a copy of which can be found in the LICENSE_STDLIB file.
module std::os::env; module std::os::env;
@@ -7,53 +7,119 @@ import libc;
/** /**
* @param [in] name * @param [in] name
* @require name.len > 0 * @require name.len > 0
* @return! SearchResult.MISSING
**/ **/
fn String! get_var(String name) fn String! get_var(String name, Allocator* using = mem::heap())
{ {
$if env::LIBC && !env::WIN32: @pool(using)
@pool()
{ {
$switch
$case env::LIBC && !env::WIN32:
ZString val = libc::getenv(name.zstr_tcopy()); ZString val = libc::getenv(name.zstr_tcopy());
return val ? val.str_view() : SearchResult.MISSING?; return val ? val.copy(using) : SearchResult.MISSING?;
$case env::WIN32:
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getenvironmentvariable
const usz BUFSIZE = 1024;
WString buff = (WString)tcalloc(BUFSIZE * 2 + 2);
WString wstr = name.to_wstring(mem::temp())!;
usz len = win32::getEnvironmentVariableW(wstr, buff, BUFSIZE);
if (len == 0) return SearchResult.MISSING?;
if (len > BUFSIZE)
{
buff = (WString)tmalloc(len * 2 + 2);
win32::getEnvironmentVariableW(wstr, buff, (Win32_DWORD)len);
}
return string::from_wstring(buff, using);
$default:
return "";
$endswitch
}; };
$else
return "";
$endif
} }
/** /**
* @param [in] name * @param [in] name
* @param [in] value * @param [in] value
* @require name.len > 0 * @require name.len > 0
**/ **/
fn void set_var(String name, String value, bool overwrite = true) fn bool set_var(String name, String value, bool overwrite = true)
{ {
$if env::LIBC && !env::WIN32:
@pool() @pool()
{ {
if (libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite)) $switch
$case env::WIN32:
WString wname = name.to_wstring(mem::temp())!!;
if (!overwrite)
{ {
unreachable(); Char16[8] buff;
if (win32::getEnvironmentVariableW(wname, &buff, 8) > 0) return true;
} }
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable
return (win32::setEnvironmentVariableW(wname, value.to_wstring(mem::temp())) ?? 1) == 0;
$case env::LIBC && !env::WIN32:
return libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite) == 0;
$default:
return false;
$endswitch
}; };
$endif
} }
/**
* Returns the current user's home directory.
**/
fn String! get_home_dir(Allocator* using = mem::heap())
{
String home;
$if !env::WIN32:
home = "HOME";
$else
home = "USERPROFILE";
$endif
return get_var(home, using);
}
/**
* Returns the current user's config directory.
**/
fn Path! get_config_dir(Allocator* using = mem::heap())
{
@pool(using)
{
$if env::WIN32:
return path::new(get_var("AppData", .using = mem::temp()), .using = using);
$else
$if env::DARWIN:
String s = get_var("HOME", .using = mem::temp())!;
const DIR = "Library/Application Support";
$else
String s = get_var("XDG_CONFIG_HOME", .using = mem::temp()) ?? get_var("HOME", .using = mem::temp())!;
const DIR = ".config";
$endif
return path::new(s, .using = mem::temp()).append(DIR, .using = using);
$endif
};
}
/** /**
* @param [in] name * @param [in] name
* @require name.len > 0 * @require name.len > 0
**/ **/
fn void clear_var(String name) fn bool clear_var(String name)
{ {
$if env::LIBC && !env::WIN32:
@pool() @pool()
{ {
if (libc::unsetenv(name.zstr_tcopy())) $switch
{ $case env::WIN32:
unreachable(); WString wname = name.to_wstring(mem::temp())!!;
} return win32::setEnvironmentVariableW(wname, null) == 0;
$case env::LIBC && !env::WIN32:
return libc::unsetenv(name.zstr_tcopy()) == 0;
$default:
return false;
$endswitch
}; };
$endif
} }
fn String! executable_path(Allocator *using = mem::heap()) fn String! executable_path(Allocator *using = mem::heap())

View File

@@ -83,7 +83,15 @@ extern fn Win32_BOOL getOverlappedResult(
Win32_LPDWORD lpNumberOfBytesTransferred, Win32_LPDWORD lpNumberOfBytesTransferred,
Win32_BOOL bWait Win32_BOOL bWait
) @extern("GetOverlappedResult"); ) @extern("GetOverlappedResult");
extern fn Win32_DWORD getEnvironmentVariableW(
Win32_LPCWSTR lpName,
Win32_LPWSTR lpBuffer,
Win32_DWORD nSize
) @extern("GetEnvironmentVariableW");
extern fn Win32_BOOL setEnvironmentVariableW(
Win32_LPCWSTR lpName,
Win32_LPCWSTR lpValue
) @extern("SetEnvironmentVariableW");
struct SystemInfo struct SystemInfo
{ {

View File

@@ -0,0 +1,17 @@
module std::os::env @test;
fn void! set_get_unset()
{
const NAME = "C3_TEST_ENVVAR";
const VALUE = "foobar";
env::set_var(NAME, VALUE);
String v = env::get_var(NAME)!;
assert(v == VALUE, "got %s; want %s", v, VALUE);
env::clear_var(NAME);
if (try env::get_var(NAME))
{
assert(false, "environment variable should no longer exist");
}
}