mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 20:58:15 +00:00
Merge branch 'master' into separate-int-word-sizes
This commit is contained in:
+19
-14
@@ -56,9 +56,9 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: Download LLVM and setup PATH
|
- name: Download LLVM, botan and setup PATH
|
||||||
run: |
|
run: |
|
||||||
brew install llvm@11
|
brew install llvm@11 botan
|
||||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||||
@@ -87,6 +87,11 @@ jobs:
|
|||||||
cd tests/core
|
cd tests/core
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Vendor library tests
|
||||||
|
run: |
|
||||||
|
cd tests/vendor
|
||||||
|
make
|
||||||
|
timeout-minutes: 10
|
||||||
- name: Odin internals tests
|
- name: Odin internals tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/internal
|
cd tests/internal
|
||||||
@@ -99,13 +104,13 @@ jobs:
|
|||||||
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
./build.bat 1
|
./build.bat 1
|
||||||
- name: Odin version
|
- name: Odin version
|
||||||
run: ./odin version
|
run: ./odin version
|
||||||
@@ -116,65 +121,65 @@ jobs:
|
|||||||
- name: Odin check
|
- name: Odin check
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin check examples/demo -vet
|
odin check examples/demo -vet
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo
|
odin run examples/demo
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run -debug
|
- name: Odin run -debug
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo -debug
|
odin run examples/demo -debug
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin check examples/all
|
- name: Odin check examples/all
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin check examples/all -strict-style
|
odin check examples/all -strict-style
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Core library tests
|
- name: Core library tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\core
|
cd tests\core
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Vendor library tests
|
- name: Vendor library tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\vendor
|
cd tests\vendor
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin internals tests
|
- name: Odin internals tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\internal
|
cd tests\internal
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin documentation tests
|
- name: Odin documentation tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\documentation
|
cd tests\documentation
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: core:math/big tests
|
- name: core:math/big tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\core\math\big
|
cd tests\core\math\big
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin check examples/all for Windows 32bits
|
- name: Odin check examples/all for Windows 32bits
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin check examples/all -strict-style -target:windows_i386
|
odin check examples/all -strict-style -target:windows_i386
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
./build.bat 1 1
|
./build.bat 1 1
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo
|
odin run examples/demo
|
||||||
- name: Copy artifacts
|
- name: Copy artifacts
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+1
-3
@@ -4,14 +4,12 @@ set -eu
|
|||||||
: ${CXX=clang++}
|
: ${CXX=clang++}
|
||||||
: ${CPPFLAGS=}
|
: ${CPPFLAGS=}
|
||||||
: ${CXXFLAGS=}
|
: ${CXXFLAGS=}
|
||||||
: ${INCLUDE_DIRECTORIES=}
|
|
||||||
: ${LDFLAGS=}
|
: ${LDFLAGS=}
|
||||||
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
||||||
: ${GIT_SHA=}
|
: ${GIT_SHA=}
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
||||||
CXXFLAGS="$CXXFLAGS -std=c++14"
|
CXXFLAGS="$CXXFLAGS -std=c++14"
|
||||||
INCLUDE_DIRECTORIES="$INCLUDE_DIRECTORIES -Isrc/"
|
|
||||||
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||||
|
|
||||||
if [ -d ".git" ]; then
|
if [ -d ".git" ]; then
|
||||||
@@ -148,7 +146,7 @@ build_odin() {
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $INCLUDE_DIRECTORIES $EXTRAFLAGS $LDFLAGS -o odin
|
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||||
set +x
|
set +x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
|
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
|
||||||
|
if b.buf == nil {
|
||||||
|
b.buf = make([dynamic]byte, len, cap, allocator)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
b.buf.allocator = allocator
|
b.buf.allocator = allocator
|
||||||
reserve(&b.buf, cap)
|
reserve(&b.buf, cap)
|
||||||
resize(&b.buf, len)
|
resize(&b.buf, len)
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package hex
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check {
|
||||||
|
dst := make([]byte, len(src) * 2, allocator)
|
||||||
|
for i, j := 0, 0; i < len(src); i += 1 {
|
||||||
|
v := src[i]
|
||||||
|
dst[j] = HEXTABLE[v>>4]
|
||||||
|
dst[j+1] = HEXTABLE[v&0x0f]
|
||||||
|
j += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check {
|
||||||
|
if len(src) % 2 == 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = make([]byte, len(src) / 2, allocator)
|
||||||
|
for i, j := 0, 1; j < len(src); j += 2 {
|
||||||
|
p := src[j-1]
|
||||||
|
q := src[j]
|
||||||
|
|
||||||
|
a := hex_digit(p) or_return
|
||||||
|
b := hex_digit(q) or_return
|
||||||
|
|
||||||
|
dst[i] = (a << 4) | b
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decodes the given sequence into one byte.
|
||||||
|
// Should be called with one byte worth of the source, eg: 0x23 -> '#'.
|
||||||
|
decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
|
||||||
|
str := str
|
||||||
|
if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
|
||||||
|
str = str[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(str) != 2 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
upper := hex_digit(str[0]) or_return
|
||||||
|
lower := hex_digit(str[1]) or_return
|
||||||
|
|
||||||
|
return upper << 4 | lower, true
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
HEXTABLE := [16]byte {
|
||||||
|
'0', '1', '2', '3',
|
||||||
|
'4', '5', '6', '7',
|
||||||
|
'8', '9', 'a', 'b',
|
||||||
|
'c', 'd', 'e', 'f',
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
hex_digit :: proc(char: byte) -> (u8, bool) {
|
||||||
|
switch char {
|
||||||
|
case '0' ..= '9': return char - '0', true
|
||||||
|
case 'a' ..= 'f': return char - 'a' + 10, true
|
||||||
|
case 'A' ..= 'F': return char - 'A' + 10, true
|
||||||
|
case: return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+14
-40
@@ -19,7 +19,7 @@ package net
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:strconv"
|
import "core:strconv"
|
||||||
import "core:unicode/utf8"
|
import "core:unicode/utf8"
|
||||||
import "core:mem"
|
import "core:encoding/hex"
|
||||||
|
|
||||||
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) {
|
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) {
|
||||||
s := url
|
s := url
|
||||||
@@ -36,9 +36,11 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
|
|||||||
s = s[:i]
|
s = s[:i]
|
||||||
if query_str != "" {
|
if query_str != "" {
|
||||||
queries_parts := strings.split(query_str, "&")
|
queries_parts := strings.split(query_str, "&")
|
||||||
|
defer delete(queries_parts)
|
||||||
queries = make(map[string]string, len(queries_parts), allocator)
|
queries = make(map[string]string, len(queries_parts), allocator)
|
||||||
for q in queries_parts {
|
for q in queries_parts {
|
||||||
parts := strings.split(q, "=")
|
parts := strings.split(q, "=")
|
||||||
|
defer delete(parts)
|
||||||
switch len(parts) {
|
switch len(parts) {
|
||||||
case 1: queries[parts[0]] = "" // NOTE(tetra): Query not set to anything, was but present.
|
case 1: queries[parts[0]] = "" // NOTE(tetra): Query not set to anything, was but present.
|
||||||
case 2: queries[parts[0]] = parts[1] // NOTE(tetra): Query set to something.
|
case 2: queries[parts[0]] = parts[1] // NOTE(tetra): Query set to something.
|
||||||
@@ -76,13 +78,19 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if len(queries) > 0 do write_string(&b, "?")
|
query_length := len(queries)
|
||||||
|
if query_length > 0 do write_string(&b, "?")
|
||||||
|
i := 0
|
||||||
for query_name, query_value in queries {
|
for query_name, query_value in queries {
|
||||||
write_string(&b, query_name)
|
write_string(&b, query_name)
|
||||||
if query_value != "" {
|
if query_value != "" {
|
||||||
write_string(&b, "=")
|
write_string(&b, "=")
|
||||||
write_string(&b, query_value)
|
write_string(&b, query_value)
|
||||||
}
|
}
|
||||||
|
if i < query_length - 1 {
|
||||||
|
write_string(&b, "&")
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return to_string(b)
|
return to_string(b)
|
||||||
@@ -119,12 +127,10 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
|
|||||||
builder_grow(&b, len(encoded_string))
|
builder_grow(&b, len(encoded_string))
|
||||||
defer if !ok do builder_destroy(&b)
|
defer if !ok do builder_destroy(&b)
|
||||||
|
|
||||||
stack_buf: [4]u8
|
|
||||||
pending := mem.buffer_from_slice(stack_buf[:])
|
|
||||||
s := encoded_string
|
s := encoded_string
|
||||||
|
|
||||||
for len(s) > 0 {
|
for len(s) > 0 {
|
||||||
i := index_rune(s, '%')
|
i := index_byte(s, '%')
|
||||||
if i == -1 {
|
if i == -1 {
|
||||||
write_string(&b, s) // no '%'s; the string is already decoded
|
write_string(&b, s) // no '%'s; the string is already decoded
|
||||||
break
|
break
|
||||||
@@ -137,47 +143,15 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
|
|||||||
s = s[1:]
|
s = s[1:]
|
||||||
|
|
||||||
if s[0] == '%' {
|
if s[0] == '%' {
|
||||||
write_rune(&b, '%')
|
write_byte(&b, '%')
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s) < 2 do return // percent without encoded value
|
if len(s) < 2 do return // percent without encoded value
|
||||||
|
|
||||||
n: int
|
val := hex.decode_sequence(s[:2]) or_return
|
||||||
n, _ = strconv.parse_int(s[:2], 16)
|
write_byte(&b, val)
|
||||||
switch n {
|
|
||||||
case 0x20: write_rune(&b, ' ')
|
|
||||||
case 0x21: write_rune(&b, '!')
|
|
||||||
case 0x23: write_rune(&b, '#')
|
|
||||||
case 0x24: write_rune(&b, '$')
|
|
||||||
case 0x25: write_rune(&b, '%')
|
|
||||||
case 0x26: write_rune(&b, '&')
|
|
||||||
case 0x27: write_rune(&b, '\'')
|
|
||||||
case 0x28: write_rune(&b, '(')
|
|
||||||
case 0x29: write_rune(&b, ')')
|
|
||||||
case 0x2A: write_rune(&b, '*')
|
|
||||||
case 0x2B: write_rune(&b, '+')
|
|
||||||
case 0x2C: write_rune(&b, ',')
|
|
||||||
case 0x2F: write_rune(&b, '/')
|
|
||||||
case 0x3A: write_rune(&b, ':')
|
|
||||||
case 0x3B: write_rune(&b, ';')
|
|
||||||
case 0x3D: write_rune(&b, '=')
|
|
||||||
case 0x3F: write_rune(&b, '?')
|
|
||||||
case 0x40: write_rune(&b, '@')
|
|
||||||
case 0x5B: write_rune(&b, '[')
|
|
||||||
case 0x5D: write_rune(&b, ']')
|
|
||||||
case:
|
|
||||||
// utf-8 bytes
|
|
||||||
// TODO(tetra): Audit this - 4 bytes???
|
|
||||||
append(&pending, s[0])
|
|
||||||
append(&pending, s[1])
|
|
||||||
if len(pending) == 4 {
|
|
||||||
r, _ := utf8.decode_rune(pending[:])
|
|
||||||
write_rune(&b, r)
|
|
||||||
clear(&pending)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = s[2:]
|
s = s[2:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-10
@@ -220,6 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
|||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
MAX_RW :: 1<<30
|
MAX_RW :: 1<<30
|
||||||
|
ERROR_EOF :: 38
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
||||||
@@ -228,11 +229,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
buf = buf[:MAX_RW]
|
buf = buf[:MAX_RW]
|
||||||
|
|
||||||
}
|
}
|
||||||
curr_offset, e := seek(fd, offset, 1)
|
|
||||||
if e != 0 {
|
|
||||||
return 0, e
|
|
||||||
}
|
|
||||||
defer seek(fd, curr_offset, 0)
|
|
||||||
|
|
||||||
o := win32.OVERLAPPED{
|
o := win32.OVERLAPPED{
|
||||||
OffsetHigh = u32(offset>>32),
|
OffsetHigh = u32(offset>>32),
|
||||||
@@ -243,6 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
|
|
||||||
h := win32.HANDLE(fd)
|
h := win32.HANDLE(fd)
|
||||||
done: win32.DWORD
|
done: win32.DWORD
|
||||||
|
e: Errno
|
||||||
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||||
e = Errno(win32.GetLastError())
|
e = Errno(win32.GetLastError())
|
||||||
done = 0
|
done = 0
|
||||||
@@ -256,11 +253,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
buf = buf[:MAX_RW]
|
buf = buf[:MAX_RW]
|
||||||
|
|
||||||
}
|
}
|
||||||
curr_offset, e := seek(fd, offset, 1)
|
|
||||||
if e != 0 {
|
|
||||||
return 0, e
|
|
||||||
}
|
|
||||||
defer seek(fd, curr_offset, 0)
|
|
||||||
|
|
||||||
o := win32.OVERLAPPED{
|
o := win32.OVERLAPPED{
|
||||||
OffsetHigh = u32(offset>>32),
|
OffsetHigh = u32(offset>>32),
|
||||||
@@ -269,6 +261,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
|
|
||||||
h := win32.HANDLE(fd)
|
h := win32.HANDLE(fd)
|
||||||
done: win32.DWORD
|
done: win32.DWORD
|
||||||
|
e: Errno
|
||||||
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||||
e = Errno(win32.GetLastError())
|
e = Errno(win32.GetLastError())
|
||||||
done = 0
|
done = 0
|
||||||
@@ -276,6 +269,16 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
return int(done), e
|
return int(done), e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
read_at returns n: 0, err: 0 on EOF
|
||||||
|
on Windows, read_at changes the position of the file cursor, on *nix, it does not.
|
||||||
|
|
||||||
|
bytes: [8]u8{}
|
||||||
|
read_at(fd, bytes, 0)
|
||||||
|
read(fd, bytes)
|
||||||
|
|
||||||
|
will read from the location twice on *nix, and from two different locations on Windows
|
||||||
|
*/
|
||||||
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
return 0, ERROR_NEGATIVE_OFFSET
|
return 0, ERROR_NEGATIVE_OFFSET
|
||||||
@@ -284,6 +287,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
|||||||
b, offset := data, offset
|
b, offset := data, offset
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
m, e := pread(fd, b, offset)
|
m, e := pread(fd, b, offset)
|
||||||
|
if e == ERROR_EOF {
|
||||||
|
err = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
err = e
|
err = e
|
||||||
break
|
break
|
||||||
@@ -294,6 +301,16 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
on Windows, write_at changes the position of the file cursor, on *nix, it does not.
|
||||||
|
|
||||||
|
bytes: [8]u8{}
|
||||||
|
write_at(fd, bytes, 0)
|
||||||
|
write(fd, bytes)
|
||||||
|
|
||||||
|
will write to the location twice on *nix, and to two different locations on Windows
|
||||||
|
*/
|
||||||
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
return 0, ERROR_NEGATIVE_OFFSET
|
return 0, ERROR_NEGATIVE_OFFSET
|
||||||
|
|||||||
+1
-1
@@ -194,7 +194,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
ptr := uintptr(aligned_mem)
|
ptr := uintptr(aligned_mem)
|
||||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||||
diff := int(aligned_ptr - ptr)
|
diff := int(aligned_ptr - ptr)
|
||||||
if (size + diff) > space {
|
if (size + diff) > space || allocated_mem == nil {
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package os2
|
|||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|
||||||
_get_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
|
_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
|
||||||
//TODO
|
//TODO
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-86
@@ -9,19 +9,20 @@ import "core:sys/unix"
|
|||||||
|
|
||||||
INVALID_HANDLE :: -1
|
INVALID_HANDLE :: -1
|
||||||
|
|
||||||
_O_RDONLY :: 0o0
|
_O_RDONLY :: 0o00000000
|
||||||
_O_WRONLY :: 0o1
|
_O_WRONLY :: 0o00000001
|
||||||
_O_RDWR :: 0o2
|
_O_RDWR :: 0o00000002
|
||||||
_O_CREAT :: 0o100
|
_O_CREAT :: 0o00000100
|
||||||
_O_EXCL :: 0o200
|
_O_EXCL :: 0o00000200
|
||||||
_O_TRUNC :: 0o1000
|
_O_NOCTTY :: 0o00000400
|
||||||
_O_APPEND :: 0o2000
|
_O_TRUNC :: 0o00001000
|
||||||
_O_NONBLOCK :: 0o4000
|
_O_APPEND :: 0o00002000
|
||||||
_O_LARGEFILE :: 0o100000
|
_O_NONBLOCK :: 0o00004000
|
||||||
_O_DIRECTORY :: 0o200000
|
_O_LARGEFILE :: 0o00100000
|
||||||
_O_NOFOLLOW :: 0o400000
|
_O_DIRECTORY :: 0o00200000
|
||||||
_O_SYNC :: 0o4010000
|
_O_NOFOLLOW :: 0o00400000
|
||||||
_O_CLOEXEC :: 0o2000000
|
_O_SYNC :: 0o04010000
|
||||||
|
_O_CLOEXEC :: 0o02000000
|
||||||
_O_PATH :: 0o10000000
|
_O_PATH :: 0o10000000
|
||||||
|
|
||||||
_AT_FDCWD :: -100
|
_AT_FDCWD :: -100
|
||||||
@@ -40,9 +41,12 @@ _file_allocator :: proc() -> runtime.Allocator {
|
|||||||
|
|
||||||
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
|
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
|
||||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||||
name_cstr := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
|
|
||||||
flags_i: int
|
// Just default to using O_NOCTTY because needing to open a controlling
|
||||||
|
// terminal would be incredibly rare. This has no effect on files while
|
||||||
|
// allowing us to open serial devices.
|
||||||
|
flags_i: int = _O_NOCTTY
|
||||||
switch flags & O_RDONLY|O_WRONLY|O_RDWR {
|
switch flags & O_RDONLY|O_WRONLY|O_RDWR {
|
||||||
case O_RDONLY: flags_i = _O_RDONLY
|
case O_RDONLY: flags_i = _O_RDONLY
|
||||||
case O_WRONLY: flags_i = _O_WRONLY
|
case O_WRONLY: flags_i = _O_WRONLY
|
||||||
@@ -56,7 +60,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error
|
|||||||
flags_i |= (_O_TRUNC * int(.Trunc in flags))
|
flags_i |= (_O_TRUNC * int(.Trunc in flags))
|
||||||
flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags))
|
flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags))
|
||||||
|
|
||||||
fd := unix.sys_open(name_cstr, flags_i, int(perm))
|
fd := unix.sys_open(name_cstr, flags_i, uint(perm))
|
||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
return nil, _get_platform_error(fd)
|
return nil, _get_platform_error(fd)
|
||||||
}
|
}
|
||||||
@@ -196,10 +200,7 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_remove :: proc(name: string) -> Error {
|
_remove :: proc(name: string) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fd := unix.sys_open(name_cstr, int(File_Flags.Read))
|
fd := unix.sys_open(name_cstr, int(File_Flags.Read))
|
||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
@@ -214,40 +215,22 @@ _remove :: proc(name: string) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_rename :: proc(old_name, new_name: string) -> Error {
|
_rename :: proc(old_name, new_name: string) -> Error {
|
||||||
old_name_cstr, old_allocated := _name_to_cstring(old_name)
|
old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
|
||||||
new_name_cstr, new_allocated := _name_to_cstring(new_name)
|
new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
|
||||||
defer if old_allocated {
|
|
||||||
delete(old_name_cstr)
|
|
||||||
}
|
|
||||||
defer if new_allocated {
|
|
||||||
delete(new_name_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr))
|
return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr))
|
||||||
}
|
}
|
||||||
|
|
||||||
_link :: proc(old_name, new_name: string) -> Error {
|
_link :: proc(old_name, new_name: string) -> Error {
|
||||||
old_name_cstr, old_allocated := _name_to_cstring(old_name)
|
old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
|
||||||
new_name_cstr, new_allocated := _name_to_cstring(new_name)
|
new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
|
||||||
defer if old_allocated {
|
|
||||||
delete(old_name_cstr)
|
|
||||||
}
|
|
||||||
defer if new_allocated {
|
|
||||||
delete(new_name_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
|
return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
|
||||||
}
|
}
|
||||||
|
|
||||||
_symlink :: proc(old_name, new_name: string) -> Error {
|
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||||
old_name_cstr, old_allocated := _name_to_cstring(old_name)
|
old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
|
||||||
new_name_cstr, new_allocated := _name_to_cstring(new_name)
|
new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
|
||||||
defer if old_allocated {
|
|
||||||
delete(old_name_cstr)
|
|
||||||
}
|
|
||||||
defer if new_allocated {
|
|
||||||
delete(new_name_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
|
return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
|
||||||
}
|
}
|
||||||
@@ -271,26 +254,17 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st
|
|||||||
}
|
}
|
||||||
|
|
||||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
|
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _read_link_cstr(name_cstr, allocator)
|
return _read_link_cstr(name_cstr, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
_unlink :: proc(name: string) -> Error {
|
_unlink :: proc(name: string) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_unlink(name_cstr))
|
return _ok_or_error(unix.sys_unlink(name_cstr))
|
||||||
}
|
}
|
||||||
|
|
||||||
_chdir :: proc(name: string) -> Error {
|
_chdir :: proc(name: string) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_chdir(name_cstr))
|
return _ok_or_error(unix.sys_chdir(name_cstr))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,32 +273,23 @@ _fchdir :: proc(f: ^File) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_chmod :: proc(name: string, mode: File_Mode) -> Error {
|
_chmod :: proc(name: string, mode: File_Mode) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode)))
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_chmod(name_cstr, int(mode)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
||||||
return _ok_or_error(unix.sys_fchmod(f.impl.fd, int(mode)))
|
return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: will throw error without super user priviledges
|
// NOTE: will throw error without super user priviledges
|
||||||
_chown :: proc(name: string, uid, gid: int) -> Error {
|
_chown :: proc(name: string, uid, gid: int) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_chown(name_cstr, uid, gid))
|
return _ok_or_error(unix.sys_chown(name_cstr, uid, gid))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: will throw error without super user priviledges
|
// NOTE: will throw error without super user priviledges
|
||||||
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid))
|
return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,10 +299,7 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
times := [2]Unix_File_Time {
|
times := [2]Unix_File_Time {
|
||||||
{ atime._nsec, 0 },
|
{ atime._nsec, 0 },
|
||||||
{ mtime._nsec, 0 },
|
{ mtime._nsec, 0 },
|
||||||
@@ -354,18 +316,12 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_exists :: proc(name: string) -> bool {
|
_exists :: proc(name: string) -> bool {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
return unix.sys_access(name_cstr, F_OK) == 0
|
return unix.sys_access(name_cstr, F_OK) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_file :: proc(name: string) -> bool {
|
_is_file :: proc(name: string) -> bool {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
s: _Stat
|
s: _Stat
|
||||||
res := unix.sys_stat(name_cstr, &s)
|
res := unix.sys_stat(name_cstr, &s)
|
||||||
if res < 0 {
|
if res < 0 {
|
||||||
@@ -384,10 +340,7 @@ _is_file_fd :: proc(fd: int) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_is_dir :: proc(name: string) -> bool {
|
_is_dir :: proc(name: string) -> bool {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
s: _Stat
|
s: _Stat
|
||||||
res := unix.sys_stat(name_cstr, &s)
|
res := unix.sys_stat(name_cstr, &s)
|
||||||
if res < 0 {
|
if res < 0 {
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
ptr := uintptr(aligned_mem)
|
ptr := uintptr(aligned_mem)
|
||||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||||
diff := int(aligned_ptr - ptr)
|
diff := int(aligned_ptr - ptr)
|
||||||
if (size + diff) > space {
|
if (size + diff) > space || allocated_mem == nil {
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
ptr := uintptr(aligned_mem)
|
ptr := uintptr(aligned_mem)
|
||||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||||
diff := int(aligned_ptr - ptr)
|
diff := int(aligned_ptr - ptr)
|
||||||
if (size + diff) > space {
|
if (size + diff) > space || allocated_mem == nil {
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,8 @@ _mkdir :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
return .Invalid_Argument
|
return .Invalid_Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
path_cstr, allocated := _name_to_cstring(path)
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer if allocated {
|
return _ok_or_error(unix.sys_mkdir(path_cstr, uint(perm & 0o777)))
|
||||||
delete(path_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
||||||
@@ -49,7 +46,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
|
new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
|
||||||
switch new_dfd {
|
switch new_dfd {
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
if res := unix.sys_mkdirat(dfd, cstring(&path[0]), perm); res < 0 {
|
if res := unix.sys_mkdirat(dfd, cstring(&path[0]), uint(perm)); res < 0 {
|
||||||
return _get_platform_error(res)
|
return _get_platform_error(res)
|
||||||
}
|
}
|
||||||
has_created^ = true
|
has_created^ = true
|
||||||
@@ -83,9 +80,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
} else {
|
} else {
|
||||||
path_bytes = make([]u8, len(path) + 1, context.temp_allocator)
|
path_bytes = make([]u8, len(path) + 1, context.temp_allocator)
|
||||||
}
|
}
|
||||||
defer if allocated {
|
|
||||||
delete(path_bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NULL terminate the byte slice to make it a valid cstring
|
// NULL terminate the byte slice to make it a valid cstring
|
||||||
copy(path_bytes, path)
|
copy(path_bytes, path)
|
||||||
@@ -182,10 +176,7 @@ _remove_all :: proc(path: string) -> Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
path_cstr, allocated := _name_to_cstring(path)
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(path_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS)
|
fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS)
|
||||||
switch fd {
|
switch fd {
|
||||||
@@ -222,10 +213,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_setwd :: proc(dir: string) -> Error {
|
_setwd :: proc(dir: string) -> Error {
|
||||||
dir_cstr, allocated := _name_to_cstring(dir)
|
dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(dir_cstr)
|
|
||||||
}
|
|
||||||
return _ok_or_error(unix.sys_chdir(dir_cstr))
|
return _ok_or_error(unix.sys_chdir(dir_cstr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package os2
|
|||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:strings"
|
||||||
import "core:sys/unix"
|
import "core:sys/unix"
|
||||||
import "core:path/filepath"
|
import "core:path/filepath"
|
||||||
|
|
||||||
@@ -112,10 +113,7 @@ _fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Er
|
|||||||
|
|
||||||
// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
|
// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
|
||||||
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fd := unix.sys_open(name_cstr, _O_RDONLY)
|
fd := unix.sys_open(name_cstr, _O_RDONLY)
|
||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
@@ -126,10 +124,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
|
fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
|
||||||
if fd < 0 {
|
if fd < 0 {
|
||||||
return {}, _get_platform_error(fd)
|
return {}, _get_platform_error(fd)
|
||||||
@@ -143,10 +139,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_stat_internal :: proc(name: string) -> (s: _Stat, res: int) {
|
_stat_internal :: proc(name: string) -> (s: _Stat, res: int) {
|
||||||
name_cstr, allocated := _name_to_cstring(name)
|
name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer if allocated {
|
|
||||||
delete(name_cstr)
|
|
||||||
}
|
|
||||||
res = unix.sys_stat(name_cstr, &s)
|
res = unix.sys_stat(name_cstr, &s)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
|
|||||||
case .Windows:
|
case .Windows:
|
||||||
dir = get_env("LocalAppData", allocator)
|
dir = get_env("LocalAppData", allocator)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.clone_safe(dir, allocator) or_return
|
dir = strings.clone(dir, allocator) or_return
|
||||||
}
|
}
|
||||||
case .Darwin:
|
case .Darwin:
|
||||||
dir = get_env("HOME", allocator)
|
dir = get_env("HOME", allocator)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
|
dir = strings.concatenate({dir, "/Library/Caches"}, allocator) or_return
|
||||||
}
|
}
|
||||||
case: // All other UNIX systems
|
case: // All other UNIX systems
|
||||||
dir = get_env("XDG_CACHE_HOME", allocator)
|
dir = get_env("XDG_CACHE_HOME", allocator)
|
||||||
@@ -22,7 +22,7 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
|
|||||||
if dir == "" {
|
if dir == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dir = strings.concatenate_safe({dir, "/.cache"}, allocator) or_return
|
dir = strings.concatenate({dir, "/.cache"}, allocator) or_return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
@@ -36,12 +36,12 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
|
|||||||
case .Windows:
|
case .Windows:
|
||||||
dir = get_env("AppData", allocator)
|
dir = get_env("AppData", allocator)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.clone_safe(dir, allocator) or_return
|
dir = strings.clone(dir, allocator) or_return
|
||||||
}
|
}
|
||||||
case .Darwin:
|
case .Darwin:
|
||||||
dir = get_env("HOME", allocator)
|
dir = get_env("HOME", allocator)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
|
dir = strings.concatenate({dir, "/Library/Application Support"}, allocator) or_return
|
||||||
}
|
}
|
||||||
case: // All other UNIX systems
|
case: // All other UNIX systems
|
||||||
dir = get_env("XDG_CACHE_HOME", allocator)
|
dir = get_env("XDG_CACHE_HOME", allocator)
|
||||||
@@ -50,7 +50,7 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
|
|||||||
if dir == "" {
|
if dir == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dir = strings.concatenate_safe({dir, "/.config"}, allocator) or_return
|
dir = strings.concatenate({dir, "/.config"}, allocator) or_return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
|
|||||||
@@ -67,16 +67,15 @@ Buffer :: struct {
|
|||||||
BUFFER_DEFAULT_SIZE :: 0x10_0000
|
BUFFER_DEFAULT_SIZE :: 0x10_0000
|
||||||
|
|
||||||
|
|
||||||
context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok {
|
context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (ctx: Context, ok: bool) #optional_ok {
|
||||||
fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600)
|
fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600)
|
||||||
if err != os.ERROR_NONE {
|
if err != os.ERROR_NONE {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.fd = fd
|
|
||||||
|
|
||||||
freq, freq_ok := time.tsc_frequency()
|
ctx.fd = fd
|
||||||
ctx.precise_time = freq_ok
|
ctx.precise_time = precise_time
|
||||||
ctx.timestamp_scale = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1
|
ctx.timestamp_scale = timestamp_scale
|
||||||
|
|
||||||
temp := [size_of(Manual_Header)]u8{}
|
temp := [size_of(Manual_Header)]u8{}
|
||||||
_build_header(temp[:], ctx.timestamp_scale)
|
_build_header(temp[:], ctx.timestamp_scale)
|
||||||
@@ -85,6 +84,14 @@ context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_o
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context_create_with_sleep :: proc(filename: string, sleep := 2 * time.Second) -> (ctx: Context, ok: bool) #optional_ok {
|
||||||
|
freq, freq_ok := time.tsc_frequency(sleep)
|
||||||
|
timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1
|
||||||
|
return context_create_with_scale(filename, freq_ok, timestamp_scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
context_create :: proc{context_create_with_scale, context_create_with_sleep}
|
||||||
|
|
||||||
context_destroy :: proc(ctx: ^Context) {
|
context_destroy :: proc(ctx: ^Context) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
prev_len := len(array)
|
prev_len := len(array)
|
||||||
resize(array, len(array)+1)
|
resize(array, len(array)+1, loc)
|
||||||
return len(array)-prev_len
|
return len(array)-prev_len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
|
|||||||
ptr := uintptr(aligned_mem)
|
ptr := uintptr(aligned_mem)
|
||||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||||
diff := int(aligned_ptr - ptr)
|
diff := int(aligned_ptr - ptr)
|
||||||
if (size + diff) > space {
|
if (size + diff) > space || allocated_mem == nil {
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ cpu_name: Maybe(string)
|
|||||||
@(init, private)
|
@(init, private)
|
||||||
init_cpu_features :: proc "c" () {
|
init_cpu_features :: proc "c" () {
|
||||||
is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool {
|
is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool {
|
||||||
return hwc&value != 0
|
return hwc&(1 << value) != 0
|
||||||
}
|
}
|
||||||
try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) {
|
try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) {
|
||||||
if is_set(hwc, value) {
|
if is_set(hwc, value) {
|
||||||
@@ -74,8 +74,15 @@ init_cpu_features :: proc "c" () {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In certain rare cases (reason unknown), XGETBV generates an
|
||||||
|
// illegal instruction, even if OSXSAVE is set per CPUID.
|
||||||
|
//
|
||||||
|
// When Chrome ran into this problem, the problem went away
|
||||||
|
// after they started checking both OSXSAVE and XSAVE.
|
||||||
|
//
|
||||||
|
// See: crbug.com/375968
|
||||||
os_supports_avx := false
|
os_supports_avx := false
|
||||||
if .os_xsave in set {
|
if .os_xsave in set && is_set(26, ecx1) {
|
||||||
eax, _ := xgetbv(0)
|
eax, _ := xgetbv(0)
|
||||||
os_supports_avx = is_set(1, eax) && is_set(2, eax)
|
os_supports_avx = is_set(1, eax) && is_set(2, eax)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -70,7 +70,7 @@ has_invariant_tsc :: proc "contextless" () -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
tsc_frequency :: proc "contextless" () -> (u64, bool) {
|
tsc_frequency :: proc "contextless" (fallback_sleep := 2 * Second) -> (u64, bool) {
|
||||||
if !has_invariant_tsc() {
|
if !has_invariant_tsc() {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ tsc_frequency :: proc "contextless" () -> (u64, bool) {
|
|||||||
tsc_begin := intrinsics.read_cycle_counter()
|
tsc_begin := intrinsics.read_cycle_counter()
|
||||||
tick_begin := tick_now()
|
tick_begin := tick_now()
|
||||||
|
|
||||||
sleep(2 * Second)
|
sleep(fallback_sleep)
|
||||||
|
|
||||||
tsc_end := intrinsics.read_cycle_counter()
|
tsc_end := intrinsics.read_cycle_counter()
|
||||||
tick_end := tick_now()
|
tick_end := tick_now()
|
||||||
|
|||||||
@@ -170,6 +170,12 @@ day :: proc "contextless" (t: Time) -> (day: int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
|
||||||
|
abs := _time_abs(t)
|
||||||
|
sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
|
||||||
|
return Weekday(int(sec) / SECONDS_PER_DAY)
|
||||||
|
}
|
||||||
|
|
||||||
clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
|
clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
|
||||||
|
|
||||||
clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
|
clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
|
||||||
|
|||||||
+5
-2
@@ -7887,8 +7887,11 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
|
|||||||
rhs.type = right_type;
|
rhs.type = right_type;
|
||||||
rhs.mode = Addressing_Value;
|
rhs.mode = Addressing_Value;
|
||||||
|
|
||||||
// TODO(bill): better error message
|
if (is_type_boolean(right_type) && is_type_boolean(end_type)) {
|
||||||
if (!check_is_assignable_to(c, &rhs, end_type)) {
|
// NOTE(bill): allow implicit conversion between boolean types
|
||||||
|
// within 'or_return' to improve the experience using third-party code
|
||||||
|
} else if (!check_is_assignable_to(c, &rhs, end_type)) {
|
||||||
|
// TODO(bill): better error message
|
||||||
gbString a = type_to_string(right_type);
|
gbString a = type_to_string(right_type);
|
||||||
gbString b = type_to_string(end_type);
|
gbString b = type_to_string(end_type);
|
||||||
gbString ret_type = type_to_string(result_type);
|
gbString ret_type = type_to_string(result_type);
|
||||||
|
|||||||
+14
-3
@@ -8,8 +8,9 @@ struct ErrorCollector {
|
|||||||
BlockingMutex string_mutex;
|
BlockingMutex string_mutex;
|
||||||
RecursiveMutex block_mutex;
|
RecursiveMutex block_mutex;
|
||||||
|
|
||||||
Array<u8> error_buffer;
|
RecursiveMutex error_buffer_mutex;
|
||||||
Array<String> errors;
|
Array<u8> error_buffer;
|
||||||
|
Array<String> errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_global ErrorCollector global_error_collector;
|
gb_global ErrorCollector global_error_collector;
|
||||||
@@ -119,6 +120,7 @@ gb_internal void begin_error_block(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void end_error_block(void) {
|
gb_internal void end_error_block(void) {
|
||||||
|
mutex_lock(&global_error_collector.error_buffer_mutex);
|
||||||
isize n = global_error_collector.error_buffer.count;
|
isize n = global_error_collector.error_buffer.count;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
u8 *text = global_error_collector.error_buffer.data;
|
u8 *text = global_error_collector.error_buffer.data;
|
||||||
@@ -150,11 +152,16 @@ gb_internal void end_error_block(void) {
|
|||||||
text = gb_alloc_array(permanent_allocator(), u8, n+1);
|
text = gb_alloc_array(permanent_allocator(), u8, n+1);
|
||||||
gb_memmove(text, global_error_collector.error_buffer.data, n);
|
gb_memmove(text, global_error_collector.error_buffer.data, n);
|
||||||
text[n] = 0;
|
text[n] = 0;
|
||||||
|
|
||||||
|
|
||||||
|
mutex_lock(&global_error_collector.error_out_mutex);
|
||||||
String s = {text, n};
|
String s = {text, n};
|
||||||
array_add(&global_error_collector.errors, s);
|
array_add(&global_error_collector.errors, s);
|
||||||
|
mutex_unlock(&global_error_collector.error_out_mutex);
|
||||||
|
|
||||||
global_error_collector.error_buffer.count = 0;
|
global_error_collector.error_buffer.count = 0;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&global_error_collector.error_buffer_mutex);
|
||||||
global_error_collector.in_block.store(false);
|
global_error_collector.in_block.store(false);
|
||||||
mutex_unlock(&global_error_collector.block_mutex);
|
mutex_unlock(&global_error_collector.block_mutex);
|
||||||
}
|
}
|
||||||
@@ -172,11 +179,15 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
|
|||||||
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
|
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
|
||||||
isize n = len-1;
|
isize n = len-1;
|
||||||
if (global_error_collector.in_block) {
|
if (global_error_collector.in_block) {
|
||||||
|
mutex_lock(&global_error_collector.error_buffer_mutex);
|
||||||
|
|
||||||
isize cap = global_error_collector.error_buffer.count + n;
|
isize cap = global_error_collector.error_buffer.count + n;
|
||||||
array_reserve(&global_error_collector.error_buffer, cap);
|
array_reserve(&global_error_collector.error_buffer, cap);
|
||||||
u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count;
|
u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count;
|
||||||
gb_memmove(data, buf, n);
|
gb_memmove(data, buf, n);
|
||||||
global_error_collector.error_buffer.count += n;
|
global_error_collector.error_buffer.count += n;
|
||||||
|
|
||||||
|
mutex_unlock(&global_error_collector.error_buffer_mutex);
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&global_error_collector.error_out_mutex);
|
mutex_lock(&global_error_collector.error_out_mutex);
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2083,10 +2083,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
|||||||
Type *elem = base_array_type(dst);
|
Type *elem = base_array_type(dst);
|
||||||
lbValue e = lb_emit_conv(p, value, elem);
|
lbValue e = lb_emit_conv(p, value, elem);
|
||||||
lbAddr v = lb_add_local_generated(p, t, false);
|
lbAddr v = lb_add_local_generated(p, t, false);
|
||||||
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
|
lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), true);
|
||||||
isize j = cast(isize)i;
|
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
|
||||||
lbValue ptr = lb_emit_matrix_epi(p, v.addr, j, j);
|
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
|
||||||
lb_emit_store(p, ptr, e);
|
lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j);
|
||||||
|
lb_emit_store(p, ptr, i == j ? e : zero);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2462,7 +2462,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
}
|
}
|
||||||
is_raw_union = true;
|
is_raw_union = true;
|
||||||
} else if (tag.string == "no_copy") {
|
} else if (tag.string == "no_copy") {
|
||||||
if (is_packed) {
|
if (no_copy) {
|
||||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||||
}
|
}
|
||||||
no_copy = true;
|
no_copy = true;
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ gb_internal gb_inline u32 ptr_map_hash_key(uintptr key) {
|
|||||||
key = key ^ (key << 28);
|
key = key ^ (key << 28);
|
||||||
res = cast(u32)key;
|
res = cast(u32)key;
|
||||||
#elif defined(GB_ARCH_32_BIT)
|
#elif defined(GB_ARCH_32_BIT)
|
||||||
u32 state = ((u32)key) * 747796405u + 2891336453u;
|
u32 state = (cast(u32)key) * 747796405u + 2891336453u;
|
||||||
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||||
res = (word >> 22u) ^ word;
|
res = (word >> 22u) ^ word;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package test_core_hex
|
||||||
|
|
||||||
|
import "core:encoding/hex"
|
||||||
|
import "core:testing"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:os"
|
||||||
|
import "core:bytes"
|
||||||
|
|
||||||
|
TEST_count := 0
|
||||||
|
TEST_fail := 0
|
||||||
|
|
||||||
|
when ODIN_TEST {
|
||||||
|
expect :: testing.expect
|
||||||
|
log :: testing.log
|
||||||
|
} else {
|
||||||
|
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||||
|
TEST_count += 1
|
||||||
|
if !condition {
|
||||||
|
TEST_fail += 1
|
||||||
|
fmt.printf("[%v] %v\n", loc, message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||||
|
fmt.printf("[%v] ", loc)
|
||||||
|
fmt.printf("log: %v\n", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
t := testing.T{}
|
||||||
|
|
||||||
|
hex_encode(&t)
|
||||||
|
hex_decode(&t)
|
||||||
|
hex_decode_sequence(&t)
|
||||||
|
|
||||||
|
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||||
|
if TEST_fail > 0 {
|
||||||
|
os.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CASES :: [][2]string{
|
||||||
|
{"11", "3131"},
|
||||||
|
{"g", "67"},
|
||||||
|
{"Hello", "48656c6c6f"},
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
hex_encode :: proc(t: ^testing.T) {
|
||||||
|
for test in CASES {
|
||||||
|
encoded := string(hex.encode(transmute([]byte)test[0]))
|
||||||
|
expect(
|
||||||
|
t,
|
||||||
|
encoded == test[1],
|
||||||
|
fmt.tprintf("encode: %q -> %q (should be: %q)", test[0], encoded, test[1]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
hex_decode :: proc(t: ^testing.T) {
|
||||||
|
for test in CASES {
|
||||||
|
decoded, ok := hex.decode(transmute([]byte)test[1])
|
||||||
|
expect(t, ok, fmt.tprintf("decode: %q not ok", test[1]))
|
||||||
|
expect(
|
||||||
|
t,
|
||||||
|
string(decoded) == test[0],
|
||||||
|
fmt.tprintf("decode: %q -> %q (should be: %q)", test[1], string(decoded), test[0]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
hex_decode_sequence :: proc(t: ^testing.T) {
|
||||||
|
b, ok := hex.decode_sequence("0x23")
|
||||||
|
expect(t, ok, "decode_sequence: 0x23 not ok")
|
||||||
|
expect(t, b == '#', fmt.tprintf("decode_sequence: 0x23 -> %c (should be: %c)", b, '#'))
|
||||||
|
|
||||||
|
b, ok = hex.decode_sequence("0X3F")
|
||||||
|
expect(t, ok, "decode_sequence: 0X3F not ok")
|
||||||
|
expect(t, b == '?', fmt.tprintf("decode_sequence: 0X3F -> %c (should be: %c)", b, '?'))
|
||||||
|
|
||||||
|
b, ok = hex.decode_sequence("2a")
|
||||||
|
expect(t, ok, "decode_sequence: 2a not ok")
|
||||||
|
expect(t, b == '*', fmt.tprintf("decode_sequence: 2a -> %c (should be: %c)", b, '*'))
|
||||||
|
|
||||||
|
_, ok = hex.decode_sequence("1")
|
||||||
|
expect(t, !ok, "decode_sequence: 1 should be too short")
|
||||||
|
|
||||||
|
_, ok = hex.decode_sequence("123")
|
||||||
|
expect(t, !ok, "decode_sequence: 123 should be too long")
|
||||||
|
}
|
||||||
@@ -67,6 +67,9 @@ main :: proc() {
|
|||||||
tcp_tests(t)
|
tcp_tests(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
split_url_test(t)
|
||||||
|
join_url_test(t)
|
||||||
|
|
||||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||||
|
|
||||||
print_tracking_allocator_report()
|
print_tracking_allocator_report()
|
||||||
@@ -509,3 +512,74 @@ client_sends_server_data :: proc(t: ^testing.T) {
|
|||||||
msg = fmt.tprintf("Expected client to send \"{}\", got \"{}\"", CONTENT, received)
|
msg = fmt.tprintf("Expected client to send \"{}\", got \"{}\"", CONTENT, received)
|
||||||
expect(t, okay, msg)
|
expect(t, okay, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
URL_Test :: struct {
|
||||||
|
scheme, host, path: string,
|
||||||
|
queries: map[string]string,
|
||||||
|
url: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
split_url_test :: proc(t: ^testing.T) {
|
||||||
|
test_cases := []URL_Test{
|
||||||
|
{ "http", "example.com", "/", {}, "http://example.com" },
|
||||||
|
{ "https", "odin-lang.org", "/", {}, "https://odin-lang.org" },
|
||||||
|
{ "https", "odin-lang.org", "/docs/", {}, "https://odin-lang.org/docs/" },
|
||||||
|
{ "https", "odin-lang.org", "/docs/overview", {}, "https://odin-lang.org/docs/overview" },
|
||||||
|
{ "http", "example.com", "/", {"a" = "b"}, "http://example.com?a=b" },
|
||||||
|
{ "http", "example.com", "/", {"a" = ""}, "http://example.com?a" },
|
||||||
|
{ "http", "example.com", "/", {"a" = "b", "c" = "d"}, "http://example.com?a=b&c=d" },
|
||||||
|
{ "http", "example.com", "/", {"a" = "", "c" = "d"}, "http://example.com?a&c=d" },
|
||||||
|
{ "http", "example.com", "/example", {"a" = "", "b" = ""}, "http://example.com/example?a&b" },
|
||||||
|
}
|
||||||
|
|
||||||
|
for test in test_cases {
|
||||||
|
scheme, host, path, queries := net.split_url(test.url)
|
||||||
|
defer {
|
||||||
|
delete(queries)
|
||||||
|
delete(test.queries)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.scheme, scheme)
|
||||||
|
expect(t, scheme == test.scheme, msg)
|
||||||
|
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.host, host)
|
||||||
|
expect(t, host == test.host, msg)
|
||||||
|
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.path, path)
|
||||||
|
expect(t, path == test.path, msg)
|
||||||
|
msg = fmt.tprintf("Expected `net.split_url` to return %d queries, got %d queries", len(test.queries), len(queries))
|
||||||
|
expect(t, len(queries) == len(test.queries), msg)
|
||||||
|
for k, v in queries {
|
||||||
|
expected := test.queries[k]
|
||||||
|
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", expected, v)
|
||||||
|
expect(t, v == expected, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@test
|
||||||
|
join_url_test :: proc(t: ^testing.T) {
|
||||||
|
test_cases := []URL_Test{
|
||||||
|
{ "http", "example.com", "", {}, "http://example.com" },
|
||||||
|
{ "https", "odin-lang.org", "", {}, "https://odin-lang.org" },
|
||||||
|
{ "https", "odin-lang.org", "docs/", {}, "https://odin-lang.org/docs/" },
|
||||||
|
{ "https", "odin-lang.org", "/docs/overview", {}, "https://odin-lang.org/docs/overview" },
|
||||||
|
{ "http", "example.com", "", {"a" = "b"}, "http://example.com?a=b" },
|
||||||
|
{ "http", "example.com", "", {"a" = ""}, "http://example.com?a" },
|
||||||
|
{ "http", "example.com", "", {"a" = "b", "c" = "d"}, "http://example.com?a=b&c=d" },
|
||||||
|
{ "http", "example.com", "", {"a" = "", "c" = "d"}, "http://example.com?a&c=d" },
|
||||||
|
{ "http", "example.com", "example", {"a" = "", "b" = ""}, "http://example.com/example?a&b" },
|
||||||
|
}
|
||||||
|
|
||||||
|
for test in test_cases {
|
||||||
|
url := net.join_url(test.scheme, test.host, test.path, test.queries)
|
||||||
|
defer {
|
||||||
|
delete(url)
|
||||||
|
delete(test.queries)
|
||||||
|
}
|
||||||
|
|
||||||
|
okay := url == test.url
|
||||||
|
msg := fmt.tprintf("Expected `net.join_url` to return %s, got %s", test.url, url)
|
||||||
|
expect(t, okay, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ set COMMON=-collection:tests=..\..
|
|||||||
|
|
||||||
..\..\..\odin test ..\test_issue_829.odin %COMMON% -file || exit /b
|
..\..\..\odin test ..\test_issue_829.odin %COMMON% -file || exit /b
|
||||||
..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file || exit /b
|
..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file || exit /b
|
||||||
|
..\..\..\odin test ..\test_issue_2056.odin %COMMON% -file || exit /b
|
||||||
..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file || exit /b
|
..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file || exit /b
|
||||||
..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b
|
..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ set -x
|
|||||||
|
|
||||||
$ODIN test ../test_issue_829.odin $COMMON -file
|
$ODIN test ../test_issue_829.odin $COMMON -file
|
||||||
$ODIN test ../test_issue_1592.odin $COMMON -file
|
$ODIN test ../test_issue_1592.odin $COMMON -file
|
||||||
|
$ODIN test ../test_issue_2056.odin $COMMON -file
|
||||||
$ODIN test ../test_issue_2087.odin $COMMON -file
|
$ODIN test ../test_issue_2087.odin $COMMON -file
|
||||||
$ODIN build ../test_issue_2113.odin $COMMON -file -debug
|
$ODIN build ../test_issue_2113.odin $COMMON -file -debug
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Tests issue #2056 https://github.com/odin-lang/Odin/issues/2056
|
||||||
|
package test_issues
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:testing"
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_scalar_matrix_conversion :: proc(t: ^testing.T) {
|
||||||
|
l := f32(1.0)
|
||||||
|
m := (matrix[4,4]f32)(l)
|
||||||
|
|
||||||
|
for i in 0..<4 {
|
||||||
|
for j in 0..<4 {
|
||||||
|
if i == j {
|
||||||
|
testing.expect(t, m[i,j] == 1, fmt.tprintf("expected 1 at m[%d,%d], found %f\n", i, j, m[i,j]))
|
||||||
|
} else {
|
||||||
|
testing.expect(t, m[i,j] == 0, fmt.tprintf("expected 0 at m[%d,%d], found %f\n", i, j, m[i,j]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+5
-5
@@ -70,8 +70,8 @@ main :: proc() {
|
|||||||
test_sha3_256(&t)
|
test_sha3_256(&t)
|
||||||
test_sha3_384(&t)
|
test_sha3_384(&t)
|
||||||
test_sha3_512(&t)
|
test_sha3_512(&t)
|
||||||
test_shake_128(&t)
|
// test_shake_128(&t)
|
||||||
test_shake_256(&t)
|
// test_shake_256(&t)
|
||||||
test_keccak_512(&t)
|
test_keccak_512(&t)
|
||||||
test_whirlpool(&t)
|
test_whirlpool(&t)
|
||||||
test_gost(&t)
|
test_gost(&t)
|
||||||
@@ -79,9 +79,9 @@ main :: proc() {
|
|||||||
test_streebog_512(&t)
|
test_streebog_512(&t)
|
||||||
test_blake2b(&t)
|
test_blake2b(&t)
|
||||||
test_ripemd_160(&t)
|
test_ripemd_160(&t)
|
||||||
test_tiger_128(&t)
|
// test_tiger_128(&t)
|
||||||
test_tiger_160(&t)
|
// test_tiger_160(&t)
|
||||||
test_tiger_192(&t)
|
// test_tiger_192(&t)
|
||||||
test_sm3(&t)
|
test_sm3(&t)
|
||||||
test_skein512_256(&t)
|
test_skein512_256(&t)
|
||||||
test_skein512_512(&t)
|
test_skein512_512(&t)
|
||||||
|
|||||||
Vendored
+2
-2
@@ -143,7 +143,7 @@ Includes full bindings as well as wrappers to match the `core:crypto` API.
|
|||||||
See also LICENSE in the `commonmark` directory itself.
|
See also LICENSE in the `commonmark` directory itself.
|
||||||
Includes full bindings and Windows `.lib` and `.dll`.
|
Includes full bindings and Windows `.lib` and `.dll`.
|
||||||
|
|
||||||
## CommonMark
|
## zlib
|
||||||
|
|
||||||
[zlib](https://github.com/madler/zlib) data compression library
|
[zlib](https://github.com/madler/zlib) data compression library
|
||||||
|
|
||||||
@@ -158,4 +158,4 @@ Includes full bindings.
|
|||||||
|
|
||||||
Used in: [bgfx](https://github.com/bkaradzic/bgfx), [Filament](https://github.com/google/filament), [gltfpack](https://github.com/zeux/meshoptimizer/tree/master/gltf), [raylib](https://github.com/raysan5/raylib), [Unigine](https://developer.unigine.com/en/docs/2.14.1/third_party?rlang=cpp#cgltf), and more!
|
Used in: [bgfx](https://github.com/bkaradzic/bgfx), [Filament](https://github.com/google/filament), [gltfpack](https://github.com/zeux/meshoptimizer/tree/master/gltf), [raylib](https://github.com/raysan5/raylib), [Unigine](https://developer.unigine.com/en/docs/2.14.1/third_party?rlang=cpp#cgltf), and more!
|
||||||
|
|
||||||
Se also LICENCE in `cgltf` directory itself.
|
See also LICENCE in `cgltf` directory itself.
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+4
-2
@@ -62,7 +62,7 @@ CRL_SIGN :: x509_cert_key_constraints(512)
|
|||||||
ENCIPHER_ONLY :: x509_cert_key_constraints(256)
|
ENCIPHER_ONLY :: x509_cert_key_constraints(256)
|
||||||
DECIPHER_ONLY :: x509_cert_key_constraints(128)
|
DECIPHER_ONLY :: x509_cert_key_constraints(128)
|
||||||
|
|
||||||
HASH_SHA1 :: "SHA1"
|
HASH_SHA1 :: "SHA-1"
|
||||||
HASH_SHA_224 :: "SHA-224"
|
HASH_SHA_224 :: "SHA-224"
|
||||||
HASH_SHA_256 :: "SHA-256"
|
HASH_SHA_256 :: "SHA-256"
|
||||||
HASH_SHA_384 :: "SHA-384"
|
HASH_SHA_384 :: "SHA-384"
|
||||||
@@ -141,7 +141,9 @@ fpe_struct :: struct{}
|
|||||||
fpe_t :: ^fpe_struct
|
fpe_t :: ^fpe_struct
|
||||||
|
|
||||||
when ODIN_OS == .Windows {
|
when ODIN_OS == .Windows {
|
||||||
foreign import botan_lib "botan.lib"
|
foreign import botan_lib "botan-3.lib"
|
||||||
|
} else when ODIN_OS == .Darwin {
|
||||||
|
foreign import botan_lib "system:botan-3"
|
||||||
} else {
|
} else {
|
||||||
foreign import botan_lib "system:botan-2"
|
foreign import botan_lib "system:botan-2"
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -44,7 +44,7 @@ REGISTRYINDEX :: -MAXSTACK - 1000
|
|||||||
** space (and to reserve some numbers for pseudo-indices).
|
** space (and to reserve some numbers for pseudo-indices).
|
||||||
** (It must fit into max(size_t)/32.)
|
** (It must fit into max(size_t)/32.)
|
||||||
*/
|
*/
|
||||||
MAXSTACK :: 1000000 when size_of(rawptr) == 4 else 15000
|
MAXSTACK :: 1000000 when size_of(rawptr) >= 4 else 15000
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user