Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get_env for Win32, @pierrec's get_config_dir and get_home_dir #1016

Merged
merged 1 commit into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/std/io/path.c3
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,17 @@ fn void Path.free(self)
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 = {
[0] = true,
['/'] = true,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/io/stream.c3
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ macro usz! Stream.write_varint(&self, x)
{
var $Type = $typeof(x);
const MAX = MAX_VARS[$Type.sizeof];
char[MAX] buffer;
char[MAX] buffer @noinit;
usz i;
while (x >= 0x80)
{
Expand Down
104 changes: 85 additions & 19 deletions lib/std/os/env.c3
Original file line number Diff line number Diff line change
@@ -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
// a copy of which can be found in the LICENSE_STDLIB file.
module std::os::env;
Expand All @@ -7,53 +7,119 @@ import libc;
/**
* @param [in] name
* @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()
@pool(using)
{
$switch
$case env::LIBC && !env::WIN32:
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] value
* @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()
{
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
};

}

/**
* 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
* @require name.len > 0
**/
fn void clear_var(String name)
fn bool clear_var(String name)
{
$if env::LIBC && !env::WIN32:
@pool()
{
if (libc::unsetenv(name.zstr_tcopy()))
{
unreachable();
}
$switch
$case env::WIN32:
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())
Expand Down
10 changes: 9 additions & 1 deletion lib/std/os/win32/process.c3
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,15 @@ extern fn Win32_BOOL getOverlappedResult(
Win32_LPDWORD lpNumberOfBytesTransferred,
Win32_BOOL bWait
) @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
{
Expand Down
17 changes: 17 additions & 0 deletions test/unit/stdlib/os/env.c3
Original file line number Diff line number Diff line change
@@ -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");
}
}