This commit is contained in:
gingerBill
2026-02-02 14:28:23 +00:00
7 changed files with 118 additions and 97 deletions

View File

@@ -6,9 +6,6 @@ import "core:strings"
import "core:strconv"
import "base:runtime"
@(private)
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc "contextless" () {
context = runtime.default_context()

View File

@@ -7,9 +7,6 @@ import "core:strings"
import "core:sys/unix"
import NS "core:sys/darwin/Foundation"
@(private)
version_string_buf: [1024]u8
@(init, private)
init_platform :: proc "contextless" () {
context = runtime.default_context()

View File

@@ -5,9 +5,6 @@ import "core:strings"
import "core:strconv"
import "base:runtime"
@(private)
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc "contextless" () {
context = runtime.default_context()

View File

@@ -7,9 +7,6 @@ import "core:strconv"
import "core:strings"
import "core:sys/linux"
@(private)
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc "contextless" () {
context = runtime.default_context()

View File

@@ -3,17 +3,12 @@ package sysinfo
import sys "core:sys/windows"
import "base:intrinsics"
import "core:strings"
import "core:strconv"
import "core:unicode/utf16"
// import "core:fmt"
import "base:runtime"
@(private)
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc "contextless" () {
// NOTE(Jeroen): Only needed for the string builder.
context = runtime.default_context()
/*
@@ -226,14 +221,14 @@ init_os_version :: proc "contextless" () {
// Grab Windows DisplayVersion (like 20H02)
format_display_version :: proc (b: ^strings.Builder) -> (version: string) {
dv, ok := read_reg_string(
scratch: [512]u8
if dv, ok := read_reg_string(
sys.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"DisplayVersion",
)
defer delete(dv) // It'll be interned into `version_string_buf`
if ok {
scratch[:],
); ok {
strings.write_string(b, " (version: ")
l := strings.builder_len(b^)
strings.write_string(b, dv)
@@ -245,13 +240,11 @@ init_os_version :: proc "contextless" () {
// Grab build number and UBR
format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) {
res, ok := read_reg_i32(
if res, ok := read_reg_i32(
sys.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"UBR",
)
if ok {
); ok {
ubr = int(res)
strings.write_string(b, ", build: ")
strings.write_int(b, major_build)
@@ -283,9 +276,6 @@ init_ram :: proc "contextless" () {
init_gpu_info :: proc "contextless" () {
GPU_ROOT_KEY :: `SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}`
context = runtime.default_context()
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
gpu_key: sys.HKEY
if status := sys.RegOpenKeyExW(
sys.HKEY_LOCAL_MACHINE,
@@ -298,16 +288,18 @@ init_gpu_info :: proc "contextless" () {
}
defer sys.RegCloseKey(gpu_key)
gpu_list: [dynamic]GPU
gpu: ^GPU
gpu_count := 0
index := sys.DWORD(0)
for {
gpu_loop: for {
defer index += 1
buf_wstring: [100]u16
buf_len := u32(len(buf_wstring))
buf_utf8: [4 * len(buf_wstring)]u8
buf_key: [4 * len(buf_wstring)]u8
buf_leaf: [100]u8
buf_scratch: [100]u8
if status := sys.RegEnumKeyW(
gpu_key,
@@ -318,59 +310,71 @@ init_gpu_info :: proc "contextless" () {
break
}
utf16.decode_to_utf8(buf_utf8[:], buf_wstring[:])
leaf := string(cstring(&buf_utf8[0]))
utf16.decode_to_utf8(buf_leaf[:], buf_wstring[:])
leaf := string(cstring(&buf_leaf[0]))
// Skip leafs that are not of the form 000x
if _, is_integer := strconv.parse_int(leaf, 10); !is_integer {
if !is_integer(leaf) {
continue
}
key := strings.concatenate({GPU_ROOT_KEY, "\\", leaf}, context.temp_allocator)
n := copy(buf_key[:], GPU_ROOT_KEY)
buf_key[n] = '\\'
copy(buf_key[n+1:], leaf)
if vendor, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName"); ok {
idx := append(&gpu_list, GPU{vendor_name = vendor})
gpu = &gpu_list[idx - 1]
key_len := len(GPU_ROOT_KEY) + len(leaf) + 1
utf16.encode_string(buf_wstring[:], string(buf_key[:key_len]))
key := cstring16(&buf_wstring[0])
if res, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName", buf_scratch[:]); ok {
if vendor, s_ok := intern_gpu_string(res); s_ok {
gpu = &_gpus[gpu_count]
gpu.vendor_name = vendor
} else {
break gpu_loop
}
} else {
continue
}
if desc, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc"); ok {
gpu.model_name = desc
if res, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc", buf_scratch[:]); ok {
if model_name, s_ok := intern_gpu_string(res); s_ok {
gpu = &_gpus[gpu_count]
gpu.model_name = model_name
} else {
break gpu_loop
}
}
if vram, ok := read_reg_i64(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize"); ok {
gpu.total_ram = int(vram)
}
gpu_count += 1
if gpu_count > MAX_GPUS {
break gpu_loop
}
}
gpus = gpu_list[:]
gpus = _gpus[:gpu_count]
}
@(private)
read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok: bool) {
read_reg_string :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16, res_buf: []u8) -> (res: string, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
result_size := sys.DWORD(BUF_SIZE * size_of(u16))
buf_utf16: [1024]u16
result_size := sys.DWORD(size_of(buf_utf16))
status := sys.RegGetValueW(
hkey,
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
subkey,
val,
sys.RRF_RT_REG_SZ,
nil,
raw_data(result_wide[:]),
raw_data(buf_utf16[:]),
&result_size,
)
if status != 0 {
@@ -378,31 +382,22 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
return
}
// Result string will be allocated for the caller.
result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
utf16.decode_to_utf8(res_buf[:result_size], buf_utf16[:])
res = string(cstring(&res_buf[0]))
return res, true
}
@(private)
read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool) {
read_reg_i32 :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16) -> (res: i32, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW(
hkey,
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
subkey,
val,
sys.RRF_RT_REG_DWORD,
nil,
&res,
@@ -410,26 +405,18 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool
)
return res, status == 0
}
@(private)
read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool) {
read_reg_i64 :: proc "contextless" (hkey: sys.HKEY, subkey, val: cstring16) -> (res: i64, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW(
hkey,
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
subkey,
val,
sys.RRF_RT_REG_QWORD,
nil,
&res,
@@ -437,3 +424,20 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool
)
return res, status == 0
}
@(private)
is_integer :: proc "contextless" (s: string) -> (ok: bool) {
if s == "" {
return
}
ok = true
for r in s {
switch r {
case '0'..='9': continue
case: return false
}
}
return
}

View File

@@ -48,3 +48,32 @@ GPU :: struct {
model_name: string,
total_ram: int,
}
@(private)
version_string_buf: [1024]u8
@(private)
MAX_GPUS :: 16
@(private)
_gpus: [MAX_GPUS]GPU
@(private)
_gpu_string_buf: [MAX_GPUS * 256 * 2]u8 // Reserve up to 256 bytes for each GPU's vendor and model name
@(private)
_gpu_string_offset: int
@(private)
intern_gpu_string :: proc "contextless" (str: string) -> (res: string, ok: bool) {
if _gpu_string_offset + len(str) + 1 > size_of(_gpu_string_buf) {
return "", false
}
n := copy(_gpu_string_buf[_gpu_string_offset:], str)
_gpu_string_buf[_gpu_string_offset + len(str)] = 0
res = string(_gpu_string_buf[_gpu_string_offset:][:len(str)])
_gpu_string_offset += n + 1
return res, true
}

View File

@@ -12,11 +12,11 @@ _surr3 :: 0xe000
_surr_self :: 0x10000
is_surrogate :: proc(r: rune) -> bool {
is_surrogate :: proc "contextless" (r: rune) -> bool {
return _surr1 <= r && r < _surr3
}
decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
decode_surrogate_pair :: proc "contextless" (r1, r2: rune) -> rune {
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self
}
@@ -24,7 +24,7 @@ decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
}
encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) {
encode_surrogate_pair :: proc "contextless" (c: rune) -> (r1, r2: rune) {
r := c
if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR
@@ -33,7 +33,7 @@ encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) {
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff
}
encode :: proc(d: []u16, s: []rune) -> int {
encode :: proc "contextless" (d: []u16, s: []rune) -> int {
n, m := 0, len(d)
loop: for r in s {
switch r {
@@ -59,7 +59,7 @@ encode :: proc(d: []u16, s: []rune) -> int {
}
encode_string :: proc(d: []u16, s: string) -> int {
encode_string :: proc "contextless" (d: []u16, s: string) -> int {
n, m := 0, len(d)
loop: for r in s {
switch r {
@@ -84,7 +84,7 @@ encode_string :: proc(d: []u16, s: string) -> int {
return n
}
decode :: proc(d: []rune, s: []u16) -> (n: int) {
decode :: proc "contextless" (d: []rune, s: []u16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
if n >= len(d) {
return
@@ -107,7 +107,7 @@ decode :: proc(d: []rune, s: []u16) -> (n: int) {
return
}
decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) {
decode_rune_in_string :: proc "contextless" (s: string16) -> (r: rune, width: int) {
r = rune(REPLACEMENT_CHAR)
n := len(s)
if n < 1 {
@@ -144,7 +144,7 @@ rune_count :: proc{
rune_count_in_string,
rune_count_in_slice,
}
rune_count_in_string :: proc(s: string16) -> (n: int) {
rune_count_in_string :: proc "contextless" (s: string16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
c := s[i]
if _surr1 <= c && c < _surr2 && i+1 < len(s) &&
@@ -157,7 +157,7 @@ rune_count_in_string :: proc(s: string16) -> (n: int) {
}
rune_count_in_slice :: proc(s: []u16) -> (n: int) {
rune_count_in_slice :: proc "contextless" (s: []u16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
c := s[i]
if _surr1 <= c && c < _surr2 && i+1 < len(s) &&
@@ -170,7 +170,7 @@ rune_count_in_slice :: proc(s: []u16) -> (n: int) {
}
decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) {
decode_to_utf8 :: proc "contextless" (d: []byte, s: []u16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
if n >= len(d) {
return
@@ -190,4 +190,4 @@ decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) {
n += copy(d[n:], b[:w])
}
return
}
}