Merge branch 'master' into strconv_docs

This commit is contained in:
Jon Lipstate
2023-04-05 22:20:21 -07:00
74 changed files with 11038 additions and 542 deletions
+2
View File
@@ -11,6 +11,8 @@ package util
*/
import "core:mem"
// Keep vet happy
_ :: mem
// @note(bp): this can replace the other two
cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D {
+2 -1
View File
@@ -163,8 +163,9 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
skip_alphanum :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
switch next_rune(t) {
switch t.r {
case 'A'..='Z', 'a'..='z', '0'..='9', '_':
next_rune(t)
continue
}
+5 -4
View File
@@ -12,10 +12,10 @@ Ascii_Set :: distinct [8]u32
/*
Creates an Ascii_Set with unique characters from the input string.
**Inputs**
Inputs:
- chars: A string containing characters to include in the Ascii_Set.
**Returns**
Returns:
- as: An Ascii_Set with unique characters from the input string.
- ok: false if any character in the input string is not a valid ASCII character.
*/
@@ -33,11 +33,12 @@ ascii_set_make :: proc(chars: string) -> (as: Ascii_Set, ok: bool) #no_bounds_ch
/*
Determines if a given char is contained within an Ascii_Set.
**Inputs**
Inputs:
- as: The Ascii_Set to search.
- c: The char to check for in the Ascii_Set.
**Returns** A boolean indicating if the byte is contained in the Ascii_Set (true) or not (false).
Returns:
A boolean indicating if the byte is contained in the Ascii_Set (true) or not (false).
*/
ascii_set_contains :: proc(as: Ascii_Set, c: byte) -> bool #no_bounds_check {
return as[c>>5] & (1<<(c&31)) != 0
+133 -91
View File
@@ -7,10 +7,11 @@ import "core:io"
/*
Type definition for a procedure that flushes a Builder
**Inputs**
Inputs:
- b: A pointer to the Builder
**Returns** A boolean indicating whether the Builder should be reset
Returns:
A boolean indicating whether the Builder should be reset
*/
Builder_Flush_Proc :: #type proc(b: ^Builder) -> (do_reset: bool)
/*
@@ -26,10 +27,11 @@ Produces a Builder with a default length of 0 and cap of 16
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- allocator: (default is context.allocator)
**Returns** A new Builder
Returns:
A new Builder
*/
builder_make_none :: proc(allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, allocator)}
@@ -39,11 +41,12 @@ Produces a Builder with a specified length and cap of max(16,len) byte buffer
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- len: The desired length of the Builder's buffer
- allocator: (default is context.allocator)
**Returns** A new Builder
Returns:
A new Builder
*/
builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, allocator)}
@@ -53,12 +56,13 @@ Produces a Builder with a specified length and cap
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- len: The desired length of the Builder's buffer
- cap: The desired capacity of the Builder's buffer, cap is max(cap, len)
- allocator: (default is context.allocator)
**Returns** A new Builder
Returns:
A new Builder
*/
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, cap, allocator)}
@@ -75,11 +79,12 @@ It replaces the existing `buf`
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- b: A pointer to the Builder
- allocator: (default is context.allocator)
**Returns** initialized ^Builder
Returns:
initialized ^Builder
*/
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, allocator)
@@ -91,12 +96,13 @@ It replaces the existing `buf`
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- b: A pointer to the Builder
- len: The desired length of the Builder's buffer
- allocator: (default is context.allocator)
**Returns** Initialized ^Builder
Returns:
Initialized ^Builder
*/
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, allocator)
@@ -106,13 +112,14 @@ builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator)
Initializes a Builder with a specified length and cap
It replaces the existing `buf`
**Inputs**
Inputs:
- b: A pointer to the Builder
- len: The desired length of the Builder's buffer
- cap: The desired capacity of the Builder's buffer, actual max(len,cap)
- allocator: (default is context.allocator)
**Returns** A pointer to the initialized Builder
Returns:
A pointer to the initialized Builder
*/
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, cap, allocator)
@@ -158,10 +165,11 @@ _builder_stream_vtable := &_builder_stream_vtable_obj
/*
Returns an io.Stream from a Builder
**Inputs**
Inputs:
- b: A pointer to the Builder
**Returns** An io.Stream
Returns:
An io.Stream
*/
to_stream :: proc(b: ^Builder) -> io.Stream {
return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b}
@@ -169,10 +177,11 @@ to_stream :: proc(b: ^Builder) -> io.Stream {
/*
Returns an io.Writer from a Builder
**Inputs**
Inputs:
- b: A pointer to the Builder
**Returns** An io.Writer
Returns:
An io.Writer
*/
to_writer :: proc(b: ^Builder) -> io.Writer {
return io.to_writer(to_stream(b))
@@ -180,7 +189,7 @@ to_writer :: proc(b: ^Builder) -> io.Writer {
/*
Deletes the Builder byte buffer content
**Inputs**
Inputs:
- b: A pointer to the Builder
*/
builder_destroy :: proc(b: ^Builder) {
@@ -190,7 +199,7 @@ builder_destroy :: proc(b: ^Builder) {
/*
Reserves the Builder byte buffer to a specific capacity, when it's higher than before
**Inputs**
Inputs:
- b: A pointer to the Builder
- cap: The desired capacity for the Builder's buffer
*/
@@ -200,7 +209,7 @@ builder_grow :: proc(b: ^Builder, cap: int) {
/*
Clears the Builder byte buffer content (sets len to zero)
**Inputs**
Inputs:
- b: A pointer to the Builder
*/
builder_reset :: proc(b: ^Builder) {
@@ -211,18 +220,23 @@ Creates a Builder from a slice of bytes with the same slice length as its capaci
*Uses Nil Allocator - Does NOT allocate*
**Inputs**
Inputs:
- backing: A slice of bytes to be used as the backing buffer
Returns:
A new Builder
Example:
import "core:fmt"
import "core:strings"
strings_builder_from_bytes_example :: proc() {
builder_from_bytes_example :: proc() {
bytes: [8]byte // <-- gets filled
builder := strings.builder_from_bytes(bytes[:])
fmt.println(strings.write_byte(&builder, 'a')) // -> "a"
fmt.println(strings.write_byte(&builder, 'b')) // -> "ab"
strings.write_byte(&builder, 'a')
fmt.println(strings.to_string(builder)) // -> "a"
strings.write_byte(&builder, 'b')
fmt.println(strings.to_string(builder)) // -> "ab"
}
Output:
@@ -230,7 +244,6 @@ Output:
a
ab
**Returns** A new Builder
*/
builder_from_bytes :: proc(backing: []byte) -> Builder {
s := transmute(runtime.Raw_Slice)backing
@@ -249,10 +262,11 @@ builder_from_slice :: builder_from_bytes
/*
Casts the Builder byte buffer to a string and returns it
**Inputs**
Inputs:
- b: A Builder
**Returns** The contents of the Builder's buffer, as a string
Returns:
The contents of the Builder's buffer, as a string
*/
to_string :: proc(b: Builder) -> string {
return string(b.buf[:])
@@ -260,10 +274,11 @@ to_string :: proc(b: Builder) -> string {
/*
Returns the length of the Builder's buffer, in bytes
**Inputs**
Inputs:
- b: A Builder
**Returns** The length of the Builder's buffer
Returns:
The length of the Builder's buffer
*/
builder_len :: proc(b: Builder) -> int {
return len(b.buf)
@@ -271,10 +286,11 @@ builder_len :: proc(b: Builder) -> int {
/*
Returns the capacity of the Builder's buffer, in bytes
**Inputs**
Inputs:
- b: A Builder
**Returns** The capacity of the Builder's buffer
Returns:
The capacity of the Builder's buffer
*/
builder_cap :: proc(b: Builder) -> int {
return cap(b.buf)
@@ -282,10 +298,11 @@ builder_cap :: proc(b: Builder) -> int {
/*
The free space left in the Builder's buffer, in bytes
**Inputs**
Inputs:
- b: A Builder
**Returns** The available space left in the Builder's buffer
Returns:
The available space left in the Builder's buffer
*/
builder_space :: proc(b: Builder) -> int {
return cap(b.buf) - len(b.buf)
@@ -293,16 +310,21 @@ builder_space :: proc(b: Builder) -> int {
/*
Appends a byte to the Builder and returns the number of bytes appended
**Inputs**
Inputs:
- b: A pointer to the Builder
- x: The byte to be appended
Returns:
The number of bytes appended
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_byte_example :: proc() {
write_byte_example :: proc() {
builder := strings.builder_make()
strings.write_byte(&builder, 'a') // 1
strings.write_byte(&builder, 'b') // 1
@@ -313,9 +335,6 @@ Output:
ab
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes appended
*/
write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
n0 := len(b.buf)
@@ -326,7 +345,7 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
/*
Appends a slice of bytes to the Builder and returns the number of bytes appended
**Inputs**
Inputs:
- b: A pointer to the Builder
- x: The slice of bytes to be appended
@@ -335,7 +354,7 @@ Example:
import "core:fmt"
import "core:strings"
strings_write_bytes_example :: proc() {
write_bytes_example :: proc() {
builder := strings.builder_make()
bytes := [?]byte { 'a', 'b', 'c' }
strings.write_bytes(&builder, bytes[:]) // 3
@@ -344,7 +363,8 @@ Example:
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes appended
Returns:
The number of bytes appended
*/
write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
n0 := len(b.buf)
@@ -355,16 +375,21 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
/*
Appends a single rune to the Builder and returns the number of bytes written and an `io.Error`
**Inputs**
Inputs:
- b: A pointer to the Builder
- r: The rune to be appended
Returns:
The number of bytes written and an io.Error (if any)
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_rune_example :: proc() {
write_rune_example :: proc() {
builder := strings.builder_make()
strings.write_rune(&builder, 'ä') // 2 None
strings.write_rune(&builder, 'b') // 1 None
@@ -375,9 +400,6 @@ Output:
äb
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written and an io.Error (if any)
*/
write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
return io.write_rune(to_writer(b), r)
@@ -385,16 +407,21 @@ write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
/*
Appends a quoted rune to the Builder and returns the number of bytes written
**Inputs**
Inputs:
- b: A pointer to the Builder
- r: The rune to be appended
Returns:
The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_quoted_rune_example :: proc() {
write_quoted_rune_example :: proc() {
builder := strings.builder_make()
strings.write_string(&builder, "abc") // 3
strings.write_quoted_rune(&builder, 'ä') // 4
@@ -406,9 +433,6 @@ Output:
abc'ä'abc
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written
*/
write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
return io.write_quoted_rune(to_writer(b), r)
@@ -416,16 +440,21 @@ write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
/*
Appends a string to the Builder and returns the number of bytes written
**Inputs**
Inputs:
- b: A pointer to the Builder
- s: The string to be appended
Returns:
The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_string_example :: proc() {
write_string_example :: proc() {
builder := strings.builder_make()
strings.write_string(&builder, "a") // 1
strings.write_string(&builder, "bc") // 2
@@ -436,9 +465,6 @@ Output:
abc
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written
*/
write_string :: proc(b: ^Builder, s: string) -> (n: int) {
n0 := len(b.buf)
@@ -449,10 +475,11 @@ write_string :: proc(b: ^Builder, s: string) -> (n: int) {
/*
Pops and returns the last byte in the Builder or 0 when the Builder is empty
**Inputs**
Inputs:
- b: A pointer to the Builder
**Returns** The last byte in the Builder or 0 if empty
Returns:
The last byte in the Builder or 0 if empty
*/
pop_byte :: proc(b: ^Builder) -> (r: byte) {
if len(b.buf) == 0 {
@@ -467,10 +494,11 @@ pop_byte :: proc(b: ^Builder) -> (r: byte) {
/*
Pops the last rune in the Builder and returns the popped rune and its rune width or (0, 0) if empty
**Inputs**
Inputs:
- b: A pointer to the Builder
**Returns** The popped rune and its rune width or (0, 0) if empty
Returns:
The popped rune and its rune width or (0, 0) if empty
*/
pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
if len(b.buf) == 0 {
@@ -485,17 +513,22 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
@(private)
DIGITS_LOWER := "0123456789abcdefx"
/*
**Inputs**
Inputs:
- b: A pointer to the Builder
- str: The string to be quoted and appended
- quote: The optional quote character (default is double quotes)
Returns:
The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_quoted_string_example :: proc() {
write_quoted_string_example :: proc() {
builder := strings.builder_make()
strings.write_quoted_string(&builder, "a") // 3
strings.write_quoted_string(&builder, "bc", '\'') // 4
@@ -507,9 +540,6 @@ Output:
"a"'bc'"xyz"
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written
*/
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
n, _ = io.write_quoted_string(to_writer(b), str, quote)
@@ -518,11 +548,16 @@ write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n:
/*
Appends a rune to the Builder and returns the number of bytes written
**Inputs**
Inputs:
- b: A pointer to the Builder
- r: The rune to be appended
- write_quote: Optional boolean flag to wrap in single-quotes (') (default is true)
Returns:
The number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
@@ -540,9 +575,6 @@ Output:
a'"'x
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written
*/
write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
n, _ = io.write_encoded_rune(to_writer(b), r, write_quote)
@@ -552,7 +584,7 @@ write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int
/*
Appends an escaped rune to the Builder and returns the number of bytes written
**Inputs**
Inputs:
- b: A pointer to the Builder
- r: The rune to be appended
- quote: The quote character
@@ -565,7 +597,8 @@ Appends an escaped rune to the Builder and returns the number of bytes written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of bytes written
Returns:
The number of bytes written
*/
write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
@@ -574,7 +607,7 @@ write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false
/*
Writes a f64 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- f: The f64 value to be appended
- fmt: The format byte
@@ -584,7 +617,8 @@ Writes a f64 value to the Builder and returns the number of characters written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
buf: [384]byte
@@ -599,7 +633,7 @@ write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_
/*
Writes a f16 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- f: The f16 value to be appended
- fmt: The format byte
@@ -607,7 +641,8 @@ Writes a f16 value to the Builder and returns the number of characters written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte
@@ -620,18 +655,23 @@ write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n:
/*
Writes a f32 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- f: The f32 value to be appended
- fmt: The format byte
- always_signed: Optional boolean flag to always include the sign
Returns:
The number of characters written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
Example:
import "core:fmt"
import "core:strings"
strings_write_f32_example :: proc() {
write_f32_example :: proc() {
builder := strings.builder_make()
strings.write_f32(&builder, 3.14159, 'f') // 6
strings.write_string(&builder, " - ") // 3
@@ -643,9 +683,6 @@ Output:
3.14159012 - -1.23000003e-01
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
*/
write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte
@@ -658,7 +695,7 @@ write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n:
/*
Writes a f32 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- f: The f32 value to be appended
- fmt: The format byte
@@ -666,7 +703,8 @@ Writes a f32 value to the Builder and returns the number of characters written
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte
@@ -679,14 +717,15 @@ write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n:
/*
Writes a u64 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- i: The u64 value to be appended
- base: The optional base for the numeric representation
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
buf: [32]byte
@@ -696,14 +735,15 @@ write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
/*
Writes a i64 value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- i: The i64 value to be appended
- base: The optional base for the numeric representation
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
buf: [32]byte
@@ -713,14 +753,15 @@ write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
/*
Writes a uint value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- i: The uint value to be appended
- base: The optional base for the numeric representation
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
return write_u64(b, u64(i), base)
@@ -728,14 +769,15 @@ write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
/*
Writes a int value to the Builder and returns the number of characters written
**Inputs**
Inputs:
- b: A pointer to the Builder
- i: The int value to be appended
- base: The optional base for the numeric representation
NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
**Returns** The number of characters written
Returns:
The number of characters written
*/
write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) {
return write_i64(b, i64(i), base)
+58 -38
View File
@@ -9,14 +9,15 @@ Converts invalid UTF-8 sequences in the input string `s` to the `replacement` st
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: Input string that may contain invalid UTF-8 sequences.
- replacement: String to replace invalid UTF-8 sequences with.
- allocator: (default: context.allocator).
WARNING: Allocation does not occur when len(s) == 0
**Returns** A valid UTF-8 string with invalid sequences replaced by `replacement`.
Returns:
A valid UTF-8 string with invalid sequences replaced by `replacement`.
*/
to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string {
if len(s) == 0 {
@@ -76,16 +77,19 @@ Converts the input string `s` to all lowercase characters.
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: Input string to be converted.
- allocator: (default: context.allocator).
Returns:
A new string with all characters converted to lowercase.
Example:
import "core:fmt"
import "core:strings"
strings_to_lower_example :: proc() {
to_lower_example :: proc() {
fmt.println(strings.to_lower("TeST"))
}
@@ -93,7 +97,6 @@ Output:
test
**Returns** A new string with all characters converted to lowercase.
*/
to_lower :: proc(s: string, allocator := context.allocator) -> string {
b: Builder
@@ -108,16 +111,19 @@ Converts the input string `s` to all uppercase characters.
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: Input string to be converted.
- allocator: (default: context.allocator).
Returns:
A new string with all characters converted to uppercase.
Example:
import "core:fmt"
import "core:strings"
strings_to_upper_example :: proc() {
to_upper_example :: proc() {
fmt.println(strings.to_upper("Test"))
}
@@ -125,7 +131,6 @@ Output:
TEST
**Returns** A new string with all characters converted to uppercase.
*/
to_upper :: proc(s: string, allocator := context.allocator) -> string {
b: Builder
@@ -138,10 +143,11 @@ to_upper :: proc(s: string, allocator := context.allocator) -> string {
/*
Checks if the rune `r` is a delimiter (' ', '-', or '_').
**Inputs**
Inputs:
- r: Rune to check for delimiter status.
**Returns** True if `r` is a delimiter, false otherwise.
Returns:
True if `r` is a delimiter, false otherwise.
*/
is_delimiter :: proc(r: rune) -> bool {
return r == '-' || r == '_' || is_space(r)
@@ -149,10 +155,11 @@ is_delimiter :: proc(r: rune) -> bool {
/*
Checks if the rune `r` is a non-alphanumeric or space character.
**Inputs**
Inputs:
- r: Rune to check for separator status.
**Returns** True if `r` is a non-alpha or `unicode.is_space` rune.
Returns:
True if `r` is a non-alpha or `unicode.is_space` rune.
*/
is_separator :: proc(r: rune) -> bool {
if r <= 0x7f {
@@ -179,7 +186,7 @@ is_separator :: proc(r: rune) -> bool {
/*
Iterates over a string, calling a callback for each rune with the previous, current, and next runes as arguments.
**Inputs**
Inputs:
- w: An io.Writer to be used by the callback for writing output.
- s: The input string to be iterated over.
- callback: A procedure to be called for each rune in the string, with arguments (w: io.Writer, prev, curr, next: rune).
@@ -191,7 +198,7 @@ Example:
import "core:strings"
import "core:io"
strings_string_case_iterator_example :: proc() {
string_case_iterator_example :: proc() {
my_callback :: proc(w: io.Writer, prev, curr, next: rune) {
fmt.println("my_callback", curr) // <-- Custom logic here
}
@@ -241,11 +248,12 @@ Converts the input string `s` to "lowerCamelCase".
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: Input string to be converted.
- allocator: (default: context.allocator).
**Returns** A "lowerCamelCase" formatted string.
Returns:
A "lowerCamelCase" formatted string.
*/
to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
@@ -275,11 +283,12 @@ Converts the input string `s` to "UpperCamelCase" (PascalCase).
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: Input string to be converted.
- allocator: (default: context.allocator).
**Returns** A "PascalCase" formatted string.
Returns:
A "PascalCase" formatted string.
*/
to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
@@ -307,18 +316,21 @@ Returns a string converted to a delimiter-separated case with configurable casin
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- delimiter: The rune to be used as the delimiter between words
- all_upper_case: A boolean indicating if the output should be all uppercased (true) or lowercased (false)
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_delimiter_case_example :: proc() {
to_delimiter_case_example :: proc() {
fmt.println(strings.to_delimiter_case("Hello World", '_', false))
fmt.println(strings.to_delimiter_case("Hello World", ' ', true))
fmt.println(strings.to_delimiter_case("aBC", '_', false))
@@ -328,9 +340,8 @@ Output:
hello_world
HELLO WORLD
a_b_c
a_bc
**Returns** The converted string
*/
to_delimiter_case :: proc(
s: string,
@@ -380,16 +391,19 @@ Converts a string to "snake_case" with all runes lowercased
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_snake_case_example :: proc() {
to_snake_case_example :: proc() {
fmt.println(strings.to_snake_case("HelloWorld"))
fmt.println(strings.to_snake_case("Hello World"))
}
@@ -399,8 +413,6 @@ Output:
hello_world
hello_world
```
**Returns** The converted string
*/
to_snake_case :: proc(s: string, allocator := context.allocator) -> string {
return to_delimiter_case(s, '_', false, allocator)
@@ -412,16 +424,19 @@ Converts a string to "SNAKE_CASE" with all runes uppercased
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_upper_snake_case_example :: proc() {
to_upper_snake_case_example :: proc() {
fmt.println(strings.to_upper_snake_case("HelloWorld"))
}
@@ -429,7 +444,6 @@ Output:
HELLO_WORLD
**Returns** The converted string
*/
to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string {
return to_delimiter_case(s, '_', true, allocator)
@@ -439,16 +453,19 @@ Converts a string to "kebab-case" with all runes lowercased
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_kebab_case_example :: proc() {
to_kebab_case_example :: proc() {
fmt.println(strings.to_kebab_case("HelloWorld"))
}
@@ -456,7 +473,6 @@ Output:
hello-world
**Returns** The converted string
*/
to_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
return to_delimiter_case(s, '-', false, allocator)
@@ -466,16 +482,19 @@ Converts a string to "KEBAB-CASE" with all runes uppercased
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_upper_kebab_case_example :: proc() {
to_upper_kebab_case_example :: proc() {
fmt.println(strings.to_upper_kebab_case("HelloWorld"))
}
@@ -483,7 +502,6 @@ Output:
HELLO-WORLD
**Returns** The converted string
*/
to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
return to_delimiter_case(s, '-', true, allocator)
@@ -493,16 +511,19 @@ Converts a string to "Ada_Case"
*Allocates Using Provided Allocator*
**Inputs**
Inputs:
- s: The input string to be converted
- allocator: (default: context.allocator).
Returns:
The converted string
Example:
import "core:fmt"
import "core:strings"
strings_to_upper_kebab_case_example :: proc() {
to_ada_case_example :: proc() {
fmt.println(strings.to_ada_case("HelloWorld"))
}
@@ -510,7 +531,6 @@ Output:
Hello_World
**Returns** The converted string
*/
to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
+11 -8
View File
@@ -25,7 +25,7 @@ Initializes the entries map and sets the allocator for the string entries
*Allocates Using Provided Allocators*
**Inputs**
Inputs:
- m: A pointer to the Intern struct to be initialized
- allocator: The allocator for the Intern_Entry strings (Default: context.allocator)
- map_allocator: The allocator for the map of entries (Default: context.allocator)
@@ -37,7 +37,7 @@ intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator :=
/*
Frees the map and all its content allocated using the `.allocator`.
**Inputs**
Inputs:
- m: A pointer to the Intern struct to be destroyed
*/
intern_destroy :: proc(m: ^Intern) {
@@ -51,13 +51,14 @@ Returns an interned copy of the given text, adding it to the map if not already
*Allocate using the Intern's Allocator (First time string is seen only)*
**Inputs**
Inputs:
- m: A pointer to the Intern struct
- text: The string to be interned
NOTE: The returned string lives as long as the map entry lives.
**Returns** The interned string and an allocator error if any
Returns:
The interned string and an allocator error if any
*/
intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
@@ -68,13 +69,14 @@ Returns an interned copy of the given text as a cstring, adding it to the map if
*Allocate using the Intern's Allocator (First time string is seen only)*
**Inputs**
Inputs:
- m: A pointer to the Intern struct
- text: The string to be interned
NOTE: The returned cstring lives as long as the map entry lives
**Returns** The interned cstring and an allocator error if any
Returns:
The interned cstring and an allocator error if any
*/
intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
@@ -86,11 +88,12 @@ Sets and allocates the entry if it wasn't set yet
*Allocate using the Intern's Allocator (First time string is seen only)*
**Inputs**
Inputs:
- m: A pointer to the Intern struct
- text: The string to be looked up or interned
**Returns** The new or existing interned entry and an allocator error if any
Returns:
The new or existing interned entry and an allocator error if any
*/
_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
if prev, ok := m.entries[text]; ok {
+34 -27
View File
@@ -16,7 +16,7 @@ Reader :: struct {
/*
Initializes a string Reader with the provided string
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- s: The input string to be read
*/
@@ -28,10 +28,11 @@ reader_init :: proc(r: ^Reader, s: string) {
/*
Converts a Reader into an `io.Stream`
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns** An io.Stream for the given Reader
Returns:
An io.Stream for the given Reader
*/
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
s.stream_data = r
@@ -41,11 +42,12 @@ reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
/*
Initializes a string Reader and returns an `io.Reader` for the given string
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- s: The input string to be read
**Returns** An io.Reader for the given string
Returns:
An io.Reader for the given string
*/
to_reader :: proc(r: ^Reader, s: string) -> io.Reader {
reader_init(r, s)
@@ -55,11 +57,12 @@ to_reader :: proc(r: ^Reader, s: string) -> io.Reader {
/*
Initializes a string Reader and returns an `io.Reader_At` for the given string
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- s: The input string to be read
**Returns** An `io.Reader_At` for the given string
Returns:
An `io.Reader_At` for the given string
*/
to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At {
reader_init(r, s)
@@ -69,10 +72,11 @@ to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At {
/*
Returns the remaining length of the Reader
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns** The remaining length of the Reader
Returns:
The remaining length of the Reader
*/
reader_length :: proc(r: ^Reader) -> int {
if r.i >= i64(len(r.s)) {
@@ -83,10 +87,11 @@ reader_length :: proc(r: ^Reader) -> int {
/*
Returns the length of the string stored in the Reader
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns** The length of the string stored in the Reader
Returns:
The length of the string stored in the Reader
*/
reader_size :: proc(r: ^Reader) -> i64 {
return i64(len(r.s))
@@ -94,11 +99,11 @@ reader_size :: proc(r: ^Reader) -> i64 {
/*
Reads len(p) bytes from the Reader's string and copies into the provided slice.
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- p: A byte slice to copy data into
**Returns**
Returns:
- n: The number of bytes read
- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
*/
@@ -114,12 +119,12 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
/*
Reads len(p) bytes from the Reader's string and copies into the provided slice, at the specified offset from the current index.
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- p: A byte slice to copy data into
- off: The offset from which to read
**Returns**
Returns:
- n: The number of bytes read
- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
*/
@@ -139,10 +144,10 @@ reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Erro
/*
Reads and returns a single byte from the Reader's string
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns**
Returns:
- The byte read from the Reader
- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
*/
@@ -158,10 +163,11 @@ reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) {
/*
Decrements the Reader's index (i) by 1
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns** An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success.
Returns:
An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success.
*/
reader_unread_byte :: proc(r: ^Reader) -> io.Error {
if r.i <= 0 {
@@ -174,10 +180,10 @@ reader_unread_byte :: proc(r: ^Reader) -> io.Error {
/*
Reads and returns a single rune and its `size` from the Reader's string
**Inputs**
Inputs:
- r: A pointer to a Reader struct
**Returns**
Returns:
- rr: The rune read from the Reader
- size: The size of the rune in bytes
- err: An `io.Error` if an error occurs while reading
@@ -199,12 +205,13 @@ reader_read_rune :: proc(r: ^Reader) -> (rr: rune, size: int, err: io.Error) {
/*
Decrements the Reader's index (i) by the size of the last read rune
**Inputs**
Inputs:
- r: A pointer to a Reader struct
WARNING: May only be used once and after a valid `read_rune` call
**Returns** An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success.
Returns:
An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success.
*/
reader_unread_rune :: proc(r: ^Reader) -> io.Error {
if r.i <= 0 {
@@ -220,12 +227,12 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error {
/*
Seeks the Reader's index to a new position
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- offset: The new offset position
- whence: The reference point for the new position (`.Start`, `.Current`, or `.End`)
**Returns**
Returns:
- The absolute offset after seeking
- err: An `io.Error` if an error occurs while seeking (`.Invalid_Whence`, `.Invalid_Offset`)
*/
@@ -252,13 +259,13 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E
/*
Writes the remaining content of the Reader's string into the provided `io.Writer`
**Inputs**
Inputs:
- r: A pointer to a Reader struct
- w: The io.Writer to write the remaining content into
WARNING: Panics if writer writes more bytes than remainig length of string.
**Returns**
Returns:
- n: The number of bytes written
- err: An io.Error if an error occurs while writing (`.Short_Write`)
*/
+409 -251
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -52,7 +52,7 @@ foreign advapi32 {
dwCreationFlags: DWORD,
lpEnvironment: LPVOID,
lpCurrentDirectory: wstring,
lpStartupInfo: LPSTARTUPINFO,
lpStartupInfo: LPSTARTUPINFOW,
lpProcessInformation: LPPROCESS_INFORMATION,
) -> BOOL ---
@@ -67,7 +67,7 @@ foreign advapi32 {
dwCreationFlags: DWORD,
lpEnvironment: LPVOID,
lpCurrentDirectory: wstring,
lpStartupInfo: LPSTARTUPINFO,
lpStartupInfo: LPSTARTUPINFOW,
lpProcessInformation: LPPROCESS_INFORMATION,
) -> BOOL ---
+81 -1
View File
@@ -193,9 +193,10 @@ foreign kernel32 {
dwCreationFlags: DWORD,
lpEnvironment: LPVOID,
lpCurrentDirectory: LPCWSTR,
lpStartupInfo: LPSTARTUPINFO,
lpStartupInfo: LPSTARTUPINFOW,
lpProcessInformation: LPPROCESS_INFORMATION,
) -> BOOL ---
GetStartupInfoW :: proc(lpStartupInfo: LPSTARTUPINFOW) ---
GetEnvironmentVariableW :: proc(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD ---
SetEnvironmentVariableW :: proc(n: LPCWSTR, v: LPCWSTR) -> BOOL ---
GetEnvironmentStringsW :: proc() -> LPWCH ---
@@ -404,8 +405,87 @@ foreign kernel32 {
) -> BOOL ---
GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setfilecompletionnotificationmodes)
SetFileCompletionNotificationModes :: proc(FileHandle: HANDLE, Flags: u8) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-createiocompletionport)
CreateIoCompletionPort :: proc(FileHandle: HANDLE, ExistingCompletionPort: HANDLE, CompletionKey: uintptr, NumberOfConcurrentThreads: DWORD) -> HANDLE ---
//[MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatus)
GetQueuedCompletionStatus :: proc(CompletionPort: HANDLE, lpNumberOfBytesTransferred: ^DWORD, lpCompletionKey: uintptr, lpOverlapped: ^^OVERLAPPED, dwMilliseconds: DWORD) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatusex)
GetQueuedCompletionStatusEx :: proc(CompletionPort: HANDLE, lpCompletionPortEntries: ^OVERLAPPED_ENTRY, ulCount: c_ulong, ulNumEntriesRemoved: ^c_ulong, dwMilliseconds: DWORD, fAlertable: BOOL) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-postqueuedcompletionstatus)
PostQueuedCompletionStatus :: proc(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: c_ulong, lpOverlapped: ^OVERLAPPED) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation)
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
}
DEBUG_PROCESS :: 0x00000001
DEBUG_ONLY_THIS_PROCESS :: 0x00000002
CREATE_SUSPENDED :: 0x00000004
DETACHED_PROCESS :: 0x00000008
CREATE_NEW_CONSOLE :: 0x00000010
NORMAL_PRIORITY_CLASS :: 0x00000020
IDLE_PRIORITY_CLASS :: 0x00000040
HIGH_PRIORITY_CLASS :: 0x00000080
REALTIME_PRIORITY_CLASS :: 0x00000100
CREATE_NEW_PROCESS_GROUP :: 0x00000200
CREATE_UNICODE_ENVIRONMENT :: 0x00000400
CREATE_SEPARATE_WOW_VDM :: 0x00000800
CREATE_SHARED_WOW_VDM :: 0x00001000
CREATE_FORCEDOS :: 0x00002000
BELOW_NORMAL_PRIORITY_CLASS :: 0x00004000
ABOVE_NORMAL_PRIORITY_CLASS :: 0x00008000
INHERIT_PARENT_AFFINITY :: 0x00010000
INHERIT_CALLER_PRIORITY :: 0x00020000 // Deprecated
CREATE_PROTECTED_PROCESS :: 0x00040000
EXTENDED_STARTUPINFO_PRESENT :: 0x00080000
PROCESS_MODE_BACKGROUND_BEGIN :: 0x00100000
PROCESS_MODE_BACKGROUND_END :: 0x00200000
CREATE_SECURE_PROCESS :: 0x00400000
CREATE_BREAKAWAY_FROM_JOB :: 0x01000000
CREATE_PRESERVE_CODE_AUTHZ_LEVEL :: 0x02000000
CREATE_DEFAULT_ERROR_MODE :: 0x04000000
CREATE_NO_WINDOW :: 0x08000000
PROFILE_USER :: 0x10000000
PROFILE_KERNEL :: 0x20000000
PROFILE_SERVER :: 0x40000000
CREATE_IGNORE_SYSTEM_DEFAULT :: 0x80000000
THREAD_BASE_PRIORITY_LOWRT :: 15 // value that gets a thread to LowRealtime-1
THREAD_BASE_PRIORITY_MAX :: 2 // maximum thread base priority boost
THREAD_BASE_PRIORITY_MIN :: (-2) // minimum thread base priority boost
THREAD_BASE_PRIORITY_IDLE :: (-15) // value that gets a thread to idle
THREAD_PRIORITY_LOWEST :: THREAD_BASE_PRIORITY_MIN
THREAD_PRIORITY_BELOW_NORMAL :: (THREAD_PRIORITY_LOWEST+1)
THREAD_PRIORITY_NORMAL :: 0
THREAD_PRIORITY_HIGHEST :: THREAD_BASE_PRIORITY_MAX
THREAD_PRIORITY_ABOVE_NORMAL :: (THREAD_PRIORITY_HIGHEST-1)
THREAD_PRIORITY_ERROR_RETURN :: (MAXLONG)
THREAD_PRIORITY_TIME_CRITICAL :: THREAD_BASE_PRIORITY_LOWRT
THREAD_PRIORITY_IDLE :: THREAD_BASE_PRIORITY_IDLE
THREAD_MODE_BACKGROUND_BEGIN :: 0x00010000
THREAD_MODE_BACKGROUND_END :: 0x00020000
COPY_FILE_FAIL_IF_EXISTS :: 0x00000001
COPY_FILE_RESTARTABLE :: 0x00000002
COPY_FILE_OPEN_SOURCE_FOR_WRITE :: 0x00000004
COPY_FILE_ALLOW_DECRYPTED_DESTINATION :: 0x00000008
COPY_FILE_COPY_SYMLINK :: 0x00000800
COPY_FILE_NO_BUFFERING :: 0x00001000
COPY_FILE_REQUEST_SECURITY_PRIVILEGES :: 0x00002000
COPY_FILE_RESUME_FROM_PAUSE :: 0x00004000
COPY_FILE_NO_OFFLOAD :: 0x00040000
COPY_FILE_IGNORE_EDP_BLOCK :: 0x00400000
COPY_FILE_IGNORE_SOURCE_ENCRYPTION :: 0x00800000
COPY_FILE_DONT_REQUEST_DEST_WRITE_DAC :: 0x02000000
COPY_FILE_REQUEST_COMPRESSED_TRAFFIC :: 0x10000000
COPY_FILE_OPEN_AND_COPY_REPARSE_POINT :: 0x00200000
COPY_FILE_DIRECTORY :: 0x00000080
COPY_FILE_SKIP_ALTERNATE_STREAMS :: 0x00008000
COPY_FILE_DISABLE_PRE_ALLOCATION :: 0x04000000
COPY_FILE_ENABLE_LOW_FREE_SPACE_MODE :: 0x08000000
SECTION_QUERY :: DWORD(0x0001)
SECTION_MAP_WRITE :: DWORD(0x0002)
+25 -31
View File
@@ -111,7 +111,7 @@ LPOVERLAPPED :: ^OVERLAPPED
LPPROCESS_INFORMATION :: ^PROCESS_INFORMATION
PSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES
LPSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES
LPSTARTUPINFO :: ^STARTUPINFO
LPSTARTUPINFOW :: ^STARTUPINFOW
LPTRACKMOUSEEVENT :: ^TRACKMOUSEEVENT
VOID :: rawptr
PVOID :: rawptr
@@ -145,8 +145,6 @@ PCONDITION_VARIABLE :: ^CONDITION_VARIABLE
PLARGE_INTEGER :: ^LARGE_INTEGER
PSRWLOCK :: ^SRWLOCK
MMRESULT :: UINT
CREATE_WAITABLE_TIMER_MANUAL_RESET :: 0x00000001
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION :: 0x00000002
@@ -164,6 +162,8 @@ SIZE :: struct {
PSIZE :: ^SIZE
LPSIZE :: ^SIZE
MAXLONG :: 0x7fffffff
FILE_ATTRIBUTE_READONLY: DWORD : 0x00000001
FILE_ATTRIBUTE_HIDDEN: DWORD : 0x00000002
FILE_ATTRIBUTE_SYSTEM: DWORD : 0x00000004
@@ -261,26 +261,6 @@ GET_FILEEX_INFO_LEVELS :: distinct i32
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1
// String resource number bases (internal use)
MMSYSERR_BASE :: 0
WAVERR_BASE :: 32
MIDIERR_BASE :: 64
TIMERR_BASE :: 96
JOYERR_BASE :: 160
MCIERR_BASE :: 256
MIXERR_BASE :: 1024
MCI_STRING_OFFSET :: 512
MCI_VD_OFFSET :: 1024
MCI_CD_OFFSET :: 1088
MCI_WAVE_OFFSET :: 1152
MCI_SEQ_OFFSET :: 1216
// timer error return values
TIMERR_NOERROR :: 0 // no error
TIMERR_NOCANDO :: TIMERR_BASE + 1 // request not completed
TIMERR_STRUCT :: TIMERR_BASE + 33 // time struct size
DIAGNOSTIC_REASON_VERSION :: 0
@@ -2064,7 +2044,6 @@ TLS_OUT_OF_INDEXES: DWORD : 0xFFFFFFFF
DLL_THREAD_DETACH: DWORD : 3
DLL_PROCESS_DETACH: DWORD : 0
CREATE_SUSPENDED :: DWORD(0x00000004)
INFINITE :: ~DWORD(0)
@@ -2073,11 +2052,6 @@ DUPLICATE_SAME_ACCESS: DWORD : 0x00000002
CONDITION_VARIABLE_INIT :: CONDITION_VARIABLE{}
SRWLOCK_INIT :: SRWLOCK{}
DETACHED_PROCESS: DWORD : 0x00000008
CREATE_NEW_CONSOLE: DWORD : 0x00000010
CREATE_NO_WINDOW: DWORD : 0x08000000
CREATE_NEW_PROCESS_GROUP: DWORD : 0x00000200
CREATE_UNICODE_ENVIRONMENT: DWORD : 0x00000400
STARTF_USESTDHANDLES: DWORD : 0x00000100
VOLUME_NAME_DOS: DWORD : 0x0
@@ -2440,8 +2414,7 @@ PROCESS_INFORMATION :: struct {
dwThreadId: DWORD,
}
// FYI: This is STARTUPINFOW, not STARTUPINFOA
STARTUPINFO :: struct {
STARTUPINFOW :: struct {
cb: DWORD,
lpReserved: LPWSTR,
lpDesktop: LPWSTR,
@@ -2472,6 +2445,20 @@ FILETIME_as_unix_nanoseconds :: proc "contextless" (ft: FILETIME) -> i64 {
return (t - 116444736000000000) * 100
}
OBJECT_ATTRIBUTES :: struct {
Length: c_ulong,
RootDirectory: HANDLE,
ObjectName: ^UNICODE_STRING,
Attributes: c_ulong,
SecurityDescriptor: rawptr,
SecurityQualityOfService: rawptr,
}
UNICODE_STRING :: struct {
Length: u16,
MaximumLength: u16,
Buffer: ^u16,
}
OVERLAPPED :: struct {
Internal: ^c_ulong,
@@ -2481,6 +2468,13 @@ OVERLAPPED :: struct {
hEvent: HANDLE,
}
OVERLAPPED_ENTRY :: struct {
lpCompletionKey: c_ulong,
lpOverlapped: ^OVERLAPPED,
Internal: c_ulong,
dwNumberOfBytesTransferred: DWORD,
}
LPOVERLAPPED_COMPLETION_ROUTINE :: #type proc "stdcall" (
dwErrorCode: DWORD,
dwNumberOfBytesTransfered: DWORD,
+2 -2
View File
@@ -457,8 +457,8 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
// err := GetLastError();
// fmt.printf("GetLastError: %v\n", err);
}
si := STARTUPINFO{}
si.cb = size_of(STARTUPINFO)
si := STARTUPINFOW{}
si.cb = size_of(STARTUPINFOW)
pi := pi
ok = bool(CreateProcessAsUserW(
+161
View File
@@ -3,9 +3,170 @@ package sys_windows
foreign import winmm "system:Winmm.lib"
MMRESULT :: UINT
@(default_calling_convention="stdcall")
foreign winmm {
timeGetDevCaps :: proc(ptc: LPTIMECAPS, cbtc: UINT) -> MMRESULT ---
timeBeginPeriod :: proc(uPeriod: UINT) -> MMRESULT ---
timeEndPeriod :: proc(uPeriod: UINT) -> MMRESULT ---
timeGetTime :: proc() -> DWORD ---
}
LPTIMECAPS :: ^TIMECAPS
TIMECAPS :: struct {
wPeriodMin: UINT,
wPeriodMax: UINT,
}
// String resource number bases (internal use)
MMSYSERR_BASE :: 0
WAVERR_BASE :: 32
MIDIERR_BASE :: 64
TIMERR_BASE :: 96
JOYERR_BASE :: 160
MCIERR_BASE :: 256
MIXERR_BASE :: 1024
MCI_STRING_OFFSET :: 512
MCI_VD_OFFSET :: 1024
MCI_CD_OFFSET :: 1088
MCI_WAVE_OFFSET :: 1152
MCI_SEQ_OFFSET :: 1216
/* general error return values */
MMSYSERR_NOERROR :: 0 /* no error */
MMSYSERR_ERROR :: MMSYSERR_BASE + 1 /* unspecified error */
MMSYSERR_BADDEVICEID :: MMSYSERR_BASE + 2 /* device ID out of range */
MMSYSERR_NOTENABLED :: MMSYSERR_BASE + 3 /* driver failed enable */
MMSYSERR_ALLOCATED :: MMSYSERR_BASE + 4 /* device already allocated */
MMSYSERR_INVALHANDLE :: MMSYSERR_BASE + 5 /* device handle is invalid */
MMSYSERR_NODRIVER :: MMSYSERR_BASE + 6 /* no device driver present */
MMSYSERR_NOMEM :: MMSYSERR_BASE + 7 /* memory allocation error */
MMSYSERR_NOTSUPPORTED :: MMSYSERR_BASE + 8 /* function isn't supported */
MMSYSERR_BADERRNUM :: MMSYSERR_BASE + 9 /* error value out of range */
MMSYSERR_INVALFLAG :: MMSYSERR_BASE + 10 /* invalid flag passed */
MMSYSERR_INVALPARAM :: MMSYSERR_BASE + 11 /* invalid parameter passed */
MMSYSERR_HANDLEBUSY :: MMSYSERR_BASE + 12 /* handle being used simultaneously on another thread (eg callback) */
MMSYSERR_INVALIDALIAS :: MMSYSERR_BASE + 13 /* specified alias not found */
MMSYSERR_BADDB :: MMSYSERR_BASE + 14 /* bad registry database */
MMSYSERR_KEYNOTFOUND :: MMSYSERR_BASE + 15 /* registry key not found */
MMSYSERR_READERROR :: MMSYSERR_BASE + 16 /* registry read error */
MMSYSERR_WRITEERROR :: MMSYSERR_BASE + 17 /* registry write error */
MMSYSERR_DELETEERROR :: MMSYSERR_BASE + 18 /* registry delete error */
MMSYSERR_VALNOTFOUND :: MMSYSERR_BASE + 19 /* registry value not found */
MMSYSERR_NODRIVERCB :: MMSYSERR_BASE + 20 /* driver does not call DriverCallback */
MMSYSERR_MOREDATA :: MMSYSERR_BASE + 21 /* more data to be returned */
MMSYSERR_LASTERROR :: MMSYSERR_BASE + 21 /* last error in range */
/* waveform audio error return values */
WAVERR_BADFORMAT :: WAVERR_BASE + 0 /* unsupported wave format */
WAVERR_STILLPLAYING :: WAVERR_BASE + 1 /* still something playing */
WAVERR_UNPREPARED :: WAVERR_BASE + 2 /* header not prepared */
WAVERR_SYNC :: WAVERR_BASE + 3 /* device is synchronous */
WAVERR_LASTERROR :: WAVERR_BASE + 3 /* last error in range */
/* MIDI error return values */
MIDIERR_UNPREPARED :: MIDIERR_BASE + 0 /* header not prepared */
MIDIERR_STILLPLAYING :: MIDIERR_BASE + 1 /* still something playing */
MIDIERR_NOMAP :: MIDIERR_BASE + 2 /* no configured instruments */
MIDIERR_NOTREADY :: MIDIERR_BASE + 3 /* hardware is still busy */
MIDIERR_NODEVICE :: MIDIERR_BASE + 4 /* port no longer connected */
MIDIERR_INVALIDSETUP :: MIDIERR_BASE + 5 /* invalid MIF */
MIDIERR_BADOPENMODE :: MIDIERR_BASE + 6 /* operation unsupported w/ open mode */
MIDIERR_DONT_CONTINUE :: MIDIERR_BASE + 7 /* thru device 'eating' a message */
MIDIERR_LASTERROR :: MIDIERR_BASE + 7 /* last error in range */
/* timer error return values */
TIMERR_NOERROR :: 0 /* no error */
TIMERR_NOCANDO :: TIMERR_BASE + 1 /* request not completed */
TIMERR_STRUCT :: TIMERR_BASE + 33 /* time struct size */
/* joystick error return values */
JOYERR_NOERROR :: 0 /* no error */
JOYERR_PARMS :: JOYERR_BASE + 5 /* bad parameters */
JOYERR_NOCANDO :: JOYERR_BASE + 6 /* request not completed */
JOYERR_UNPLUGGED :: JOYERR_BASE + 7 /* joystick is unplugged */
/* MCI error return values */
MCIERR_INVALID_DEVICE_ID :: MCIERR_BASE + 1
MCIERR_UNRECOGNIZED_KEYWORD :: MCIERR_BASE + 3
MCIERR_UNRECOGNIZED_COMMAND :: MCIERR_BASE + 5
MCIERR_HARDWARE :: MCIERR_BASE + 6
MCIERR_INVALID_DEVICE_NAME :: MCIERR_BASE + 7
MCIERR_OUT_OF_MEMORY :: MCIERR_BASE + 8
MCIERR_DEVICE_OPEN :: MCIERR_BASE + 9
MCIERR_CANNOT_LOAD_DRIVER :: MCIERR_BASE + 10
MCIERR_MISSING_COMMAND_STRING :: MCIERR_BASE + 11
MCIERR_PARAM_OVERFLOW :: MCIERR_BASE + 12
MCIERR_MISSING_STRING_ARGUMENT :: MCIERR_BASE + 13
MCIERR_BAD_INTEGER :: MCIERR_BASE + 14
MCIERR_PARSER_INTERNAL :: MCIERR_BASE + 15
MCIERR_DRIVER_INTERNAL :: MCIERR_BASE + 16
MCIERR_MISSING_PARAMETER :: MCIERR_BASE + 17
MCIERR_UNSUPPORTED_FUNCTION :: MCIERR_BASE + 18
MCIERR_FILE_NOT_FOUND :: MCIERR_BASE + 19
MCIERR_DEVICE_NOT_READY :: MCIERR_BASE + 20
MCIERR_INTERNAL :: MCIERR_BASE + 21
MCIERR_DRIVER :: MCIERR_BASE + 22
MCIERR_CANNOT_USE_ALL :: MCIERR_BASE + 23
MCIERR_MULTIPLE :: MCIERR_BASE + 24
MCIERR_EXTENSION_NOT_FOUND :: MCIERR_BASE + 25
MCIERR_OUTOFRANGE :: MCIERR_BASE + 26
MCIERR_FLAGS_NOT_COMPATIBLE :: MCIERR_BASE + 28
MCIERR_FILE_NOT_SAVED :: MCIERR_BASE + 30
MCIERR_DEVICE_TYPE_REQUIRED :: MCIERR_BASE + 31
MCIERR_DEVICE_LOCKED :: MCIERR_BASE + 32
MCIERR_DUPLICATE_ALIAS :: MCIERR_BASE + 33
MCIERR_BAD_CONSTANT :: MCIERR_BASE + 34
MCIERR_MUST_USE_SHAREABLE :: MCIERR_BASE + 35
MCIERR_MISSING_DEVICE_NAME :: MCIERR_BASE + 36
MCIERR_BAD_TIME_FORMAT :: MCIERR_BASE + 37
MCIERR_NO_CLOSING_QUOTE :: MCIERR_BASE + 38
MCIERR_DUPLICATE_FLAGS :: MCIERR_BASE + 39
MCIERR_INVALID_FILE :: MCIERR_BASE + 40
MCIERR_NULL_PARAMETER_BLOCK :: MCIERR_BASE + 41
MCIERR_UNNAMED_RESOURCE :: MCIERR_BASE + 42
MCIERR_NEW_REQUIRES_ALIAS :: MCIERR_BASE + 43
MCIERR_NOTIFY_ON_AUTO_OPEN :: MCIERR_BASE + 44
MCIERR_NO_ELEMENT_ALLOWED :: MCIERR_BASE + 45
MCIERR_NONAPPLICABLE_FUNCTION :: MCIERR_BASE + 46
MCIERR_ILLEGAL_FOR_AUTO_OPEN :: MCIERR_BASE + 47
MCIERR_FILENAME_REQUIRED :: MCIERR_BASE + 48
MCIERR_EXTRA_CHARACTERS :: MCIERR_BASE + 49
MCIERR_DEVICE_NOT_INSTALLED :: MCIERR_BASE + 50
MCIERR_GET_CD :: MCIERR_BASE + 51
MCIERR_SET_CD :: MCIERR_BASE + 52
MCIERR_SET_DRIVE :: MCIERR_BASE + 53
MCIERR_DEVICE_LENGTH :: MCIERR_BASE + 54
MCIERR_DEVICE_ORD_LENGTH :: MCIERR_BASE + 55
MCIERR_NO_INTEGER :: MCIERR_BASE + 56
MCIERR_WAVE_OUTPUTSINUSE :: MCIERR_BASE + 64
MCIERR_WAVE_SETOUTPUTINUSE :: MCIERR_BASE + 65
MCIERR_WAVE_INPUTSINUSE :: MCIERR_BASE + 66
MCIERR_WAVE_SETINPUTINUSE :: MCIERR_BASE + 67
MCIERR_WAVE_OUTPUTUNSPECIFIED :: MCIERR_BASE + 68
MCIERR_WAVE_INPUTUNSPECIFIED :: MCIERR_BASE + 69
MCIERR_WAVE_OUTPUTSUNSUITABLE :: MCIERR_BASE + 70
MCIERR_WAVE_SETOUTPUTUNSUITABLE :: MCIERR_BASE + 71
MCIERR_WAVE_INPUTSUNSUITABLE :: MCIERR_BASE + 72
MCIERR_WAVE_SETINPUTUNSUITABLE :: MCIERR_BASE + 73
MCIERR_SEQ_DIV_INCOMPATIBLE :: MCIERR_BASE + 80
MCIERR_SEQ_PORT_INUSE :: MCIERR_BASE + 81
MCIERR_SEQ_PORT_NONEXISTENT :: MCIERR_BASE + 82
MCIERR_SEQ_PORT_MAPNODEVICE :: MCIERR_BASE + 83
MCIERR_SEQ_PORT_MISCERROR :: MCIERR_BASE + 84
MCIERR_SEQ_TIMER :: MCIERR_BASE + 85
MCIERR_SEQ_PORTUNSPECIFIED :: MCIERR_BASE + 86
MCIERR_SEQ_NOMIDIPRESENT :: MCIERR_BASE + 87
MCIERR_NO_WINDOW :: MCIERR_BASE + 90
MCIERR_CREATEWINDOW :: MCIERR_BASE + 91
MCIERR_FILE_READ :: MCIERR_BASE + 92
MCIERR_FILE_WRITE :: MCIERR_BASE + 93
MCIERR_NO_IDENTITY :: MCIERR_BASE + 94
/* MMRESULT error return values specific to the mixer API */
MIXERR_INVALLINE :: (MIXERR_BASE + 0)
MIXERR_INVALCONTROL :: (MIXERR_BASE + 1)
MIXERR_INVALVALUE :: (MIXERR_BASE + 2)
MIXERR_LASTERROR :: (MIXERR_BASE + 2)
+94 -3
View File
@@ -1,18 +1,78 @@
// +build windows
package sys_windows
foreign import ws2_32 "system:Ws2_32.lib"
// Define flags to be used with the WSAAsyncSelect() call.
FD_READ :: 0x01
FD_WRITE :: 0x02
FD_OOB :: 0x04
FD_ACCEPT :: 0x08
FD_CONNECT :: 0x10
FD_CLOSE :: 0x20
FD_MAX_EVENTS :: 10
INADDR_LOOPBACK :: 0x7f000001
// Event flag definitions for WSAPoll().
POLLRDNORM :: 0x0100
POLLRDBAND :: 0x0200
POLLIN :: (POLLRDNORM | POLLRDBAND)
POLLPRI :: 0x0400
POLLWRNORM :: 0x0010
POLLOUT :: (POLLWRNORM)
POLLWRBAND :: 0x0020
POLLERR :: 0x0001
POLLHUP :: 0x0002
POLLNVAL :: 0x0004
WSA_POLLFD::struct{
fd:SOCKET,
events:c_short,
revents:c_short,
}
WSANETWORKEVENTS :: struct {
lNetworkEvents: c_long,
iErrorCode: [FD_MAX_EVENTS]c_int,
}
WSAEVENT :: HANDLE
WSAID_ACCEPTEX :: GUID{0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
WSAID_GETACCEPTEXSOCKADDRS :: GUID{0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
SIO_GET_EXTENSION_FUNCTION_POINTER :: IOC_INOUT | IOC_WS2 | 6
IOC_OUT :: 0x40000000
IOC_IN :: 0x80000000
IOC_INOUT :: (IOC_IN | IOC_OUT)
IOC_WS2 :: 0x08000000
/*
Example Load:
load_accept_ex :: proc(listener: SOCKET, fn_acceptex: rawptr) {
bytes: u32
guid_accept_ex := WSAID_ACCEPTEX
rc := WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, size_of(guid_accept_ex),
fn_acceptex, size_of(fn_acceptex), &bytes, nil, nil,)
assert(rc != windows.SOCKET_ERROR)
}
*/
foreign import ws2_32 "system:Ws2_32.lib"
@(default_calling_convention="stdcall")
foreign ws2_32 {
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup)
WSAStartup :: proc(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsacleanup)
WSACleanup :: proc() -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsagetlasterror)
WSAGetLastError :: proc() -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll)
WSAPoll :: proc(fdArray: ^WSA_POLLFD, fds: c_ulong, timeout: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw)
WSADuplicateSocketW :: proc(
s: SOCKET,
dwProcessId: DWORD,
lpProtocolInfo: LPWSAPROTOCOL_INFO,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasend)
WSASend :: proc(
s: SOCKET,
lpBuffers: LPWSABUF,
@@ -22,6 +82,7 @@ foreign ws2_32 {
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecv)
WSARecv :: proc(
s: SOCKET,
lpBuffers: LPWSABUF,
@@ -31,6 +92,7 @@ foreign ws2_32 {
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw)
WSASocketW :: proc(
af: c_int,
kind: c_int,
@@ -39,16 +101,32 @@ foreign ws2_32 {
g: GROUP,
dwFlags: DWORD,
) -> SOCKET ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl)
WSAIoctl :: proc(s: SOCKET, dwIoControlCode: DWORD, lpvInBuffer: rawptr, cbInBuffer: DWORD, lpvOutBuffer: rawptr, cbOutBuffer: DWORD, lpcbBytesReturned: ^DWORD, lpOverlapped: ^OVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaeventselect)
WSAEventSelect :: proc(s: SOCKET, hEventObject: WSAEVENT, lNetworkEvents: i32) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsawaitformultipleevents)
WSAWaitForMultipleEvents :: proc(cEvents: DWORD, lphEvents: ^WSAEVENT, fWaitAll: BOOL, dwTimeout: DWORD, fAlertable: BOOL) -> DWORD ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaenumnetworkevents)
WSAEnumNetworkEvents :: proc(s: SOCKET, hEventObject: WSAEVENT, lpNetworkEvents: ^WSANETWORKEVENTS) -> c_int ---
//[MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsagetoverlappedresult)
WSAGetOverlappedResult :: proc(s: SOCKET, lpOverlapped: ^OVERLAPPED, lpcbTransfer: ^DWORD, fWait: BOOL, lpdwFlags: ^DWORD) -> BOOL ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket)
socket :: proc(
af: c_int,
type: c_int,
protocol: c_int,
) -> SOCKET ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ioctlsocket)
ioctlsocket :: proc(s: SOCKET, cmd: c_long, argp: ^c_ulong) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket)
closesocket :: proc(socket: SOCKET) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv)
recv :: proc(socket: SOCKET, buf: rawptr, len: c_int, flags: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send)
send :: proc(socket: SOCKET, buf: rawptr, len: c_int, flags: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom)
recvfrom :: proc(
socket: SOCKET,
buf: rawptr,
@@ -57,6 +135,7 @@ foreign ws2_32 {
addr: ^SOCKADDR_STORAGE_LH,
addrlen: ^c_int,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto)
sendto :: proc(
socket: SOCKET,
buf: rawptr,
@@ -65,9 +144,12 @@ foreign ws2_32 {
addr: ^SOCKADDR_STORAGE_LH,
addrlen: c_int,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown)
shutdown :: proc(socket: SOCKET, how: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept)
accept :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: ^c_int) -> SOCKET ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt)
setsockopt :: proc(
s: SOCKET,
level: c_int,
@@ -75,19 +157,28 @@ foreign ws2_32 {
optval: rawptr,
optlen: c_int,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockname)
getsockname :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: ^c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getpeername)
getpeername :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: ^c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind)
bind :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, address_len: socklen_t) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen)
listen :: proc(socket: SOCKET, backlog: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect)
connect :: proc(socket: SOCKET, address: ^SOCKADDR_STORAGE_LH, len: c_int) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo)
getaddrinfo :: proc(
node: cstring,
service: cstring,
hints: ^ADDRINFOA,
res: ^^ADDRINFOA,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-freeaddrinfo)
freeaddrinfo :: proc(res: ^ADDRINFOA) ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-freeaddrinfoexw)
FreeAddrInfoExW :: proc(pAddrInfoEx: PADDRINFOEXW) ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfoexw)
GetAddrInfoExW :: proc(
pName: PCWSTR,
pServiceName: PCWSTR,
@@ -99,7 +190,7 @@ foreign ws2_32 {
lpOverlapped: LPOVERLAPPED,
lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE,
lpHandle: LPHANDLE) -> INT ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select)
select :: proc(
nfds: c_int,
readfds: ^fd_set,
@@ -107,6 +198,7 @@ foreign ws2_32 {
exceptfds: ^fd_set,
timeout: ^timeval,
) -> c_int ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt)
getsockopt :: proc(
s: SOCKET,
level: c_int,
@@ -114,5 +206,4 @@ foreign ws2_32 {
optval: ^c_char,
optlen: ^c_int,
) -> c_int ---
}
+100
View File
@@ -0,0 +1,100 @@
/*
package table implements ascii/markdown/html/custom rendering of tables.
---
Custom rendering example:
```odin
tbl := init(&Table{})
padding(tbl, 0, 1)
row(tbl, "A_LONG_ENUM", "= 54,", "// A comment about A_LONG_ENUM")
row(tbl, "AN_EVEN_LONGER_ENUM", "= 1,", "// A comment about AN_EVEN_LONGER_ENUM")
build(tbl)
for row in 0..<tbl.nr_rows {
for col in 0..<tbl.nr_cols {
write_table_cell(stdio_writer(), tbl, row, col)
}
io.write_byte(stdio_writer(), '\n')
}
```
This outputs:
```
A_LONG_ENUM = 54, // A comment about A_LONG_ENUM
AN_EVEN_LONGER_ENUM = 1, // A comment about AN_EVEN_LONGER_ENUM
```
---
ASCII rendering example:
```odin
tbl := init(&Table{})
defer destroy(tbl)
caption(tbl, "This is a table caption and it is very long")
padding(tbl, 1, 1) // Left/right padding of cells
header(tbl, "AAAAAAAAA", "B")
header(tbl, "C") // Appends to previous header row. Same as if done header("AAAAAAAAA", "B", "C") from start.
// Create a row with two values. Since there are three columns the third
// value will become the empty string.
//
// NOTE: header() is not allowed anymore after this.
row(tbl, 123, "foo")
// Use `format()` if you need custom formatting. This will allocate into
// the arena specified at init.
row(tbl,
format(tbl, "%09d", 5),
format(tbl, "%.6f", 6.28318530717958647692528676655900576))
// A row with zero values is allowed as long as a previous row or header
// exist. The value and alignment of each cell can then be set
// individually.
row(tbl)
set_cell_value_and_alignment(tbl, last_row(tbl), 0, "a", .Center)
set_cell_value(tbl, last_row(tbl), 1, "bbb")
set_cell_value(tbl, last_row(tbl), 2, "c")
// Headers are regular cells, too. Use header_row() as row index to modify
// header cells.
set_cell_alignment(tbl, header_row(tbl), 1, .Center) // Sets alignment of 'B' column to Center.
set_cell_alignment(tbl, header_row(tbl), 2, .Right) // Sets alignment of 'C' column to Right.
build(tbl)
write_ascii_table(stdio_writer(), tbl)
write_markdown_table(stdio_writer(), tbl)
```
This outputs:
```
+-----------------------------------------------+
| This is a table caption and it is very long |
+------------------+-----------------+----------+
| AAAAAAAAA | B | C |
+------------------+-----------------+----------+
| 123 | foo | |
| 000000005 | 6.283185 | |
| a | bbb | c |
+------------------+-----------------+----------+
```
and
```
| AAAAAAAAA | B | C |
|:-----------------|:---------------:|---------:|
| 123 | foo | |
| 000000005 | 6.283185 | |
| a | bbb | c |
```
respectively.
*/
package text_table
+384
View File
@@ -0,0 +1,384 @@
/*
Copyright 2023 oskarnp <oskarnp@proton.me>
Made available under Odin's BSD-3 license.
List of contributors:
oskarnp: Initial implementation.
*/
package text_table
import "core:io"
import "core:os"
import "core:fmt"
import "core:mem"
import "core:mem/virtual"
import "core:runtime"
import "core:strings"
Cell :: struct {
text: string,
alignment: Cell_Alignment,
}
Cell_Alignment :: enum {
Left,
Center,
Right,
}
Table :: struct {
lpad, rpad: int, // Cell padding (left/right)
cells: [dynamic]Cell,
caption: string,
nr_rows, nr_cols: int,
has_header_row: bool,
table_allocator: runtime.Allocator, // Used for allocating cells/colw
format_allocator: runtime.Allocator, // Used for allocating Cell.text when applicable
dirty: bool, // True if build() needs to be called before rendering
// The following are computed on build()
colw: [dynamic]int, // Width of each column (including padding, excluding borders)
tblw: int, // Width of entire table (including padding, excluding borders)
}
init :: proc{init_with_allocator, init_with_virtual_arena, init_with_mem_arena}
init_with_allocator :: proc(tbl: ^Table, format_allocator := context.temp_allocator, table_allocator := context.allocator) -> ^Table {
tbl.table_allocator = table_allocator
tbl.cells = make([dynamic]Cell, tbl.table_allocator)
tbl.colw = make([dynamic]int, tbl.table_allocator)
tbl.format_allocator = format_allocator
return tbl
}
init_with_virtual_arena :: proc(tbl: ^Table, format_arena: ^virtual.Arena, table_allocator := context.allocator) -> ^Table {
return init_with_allocator(tbl, virtual.arena_allocator(format_arena), table_allocator)
}
init_with_mem_arena :: proc(tbl: ^Table, format_arena: ^mem.Arena, table_allocator := context.allocator) -> ^Table {
return init_with_allocator(tbl, mem.arena_allocator(format_arena), table_allocator)
}
destroy :: proc(tbl: ^Table) {
free_all(tbl.format_allocator)
delete(tbl.cells)
delete(tbl.colw)
}
caption :: proc(tbl: ^Table, value: string) {
tbl.caption = value
tbl.dirty = true
}
padding :: proc(tbl: ^Table, lpad, rpad: int) {
tbl.lpad = lpad
tbl.rpad = rpad
tbl.dirty = true
}
get_cell :: proc(tbl: ^Table, row, col: int, loc := #caller_location) -> ^Cell {
assert(col >= 0 && col < tbl.nr_cols, "cell column out of range", loc)
assert(row >= 0 && row < tbl.nr_rows, "cell row out of range", loc)
resize(&tbl.cells, tbl.nr_cols * tbl.nr_rows)
return &tbl.cells[row*tbl.nr_cols + col]
}
set_cell_value_and_alignment :: proc(tbl: ^Table, row, col: int, value: string, alignment: Cell_Alignment) {
cell := get_cell(tbl, row, col)
cell.text = format(tbl, "%v", value)
cell.alignment = alignment
tbl.dirty = true
}
set_cell_value :: proc(tbl: ^Table, row, col: int, value: any, loc := #caller_location) {
cell := get_cell(tbl, row, col, loc)
switch val in value {
case nil:
cell.text = ""
case string:
cell.text = string(val)
case cstring:
cell.text = string(val)
case:
cell.text = format(tbl, "%v", val)
if cell.text == "" {
fmt.eprintf("{} text/table: format() resulted in empty string (arena out of memory?)\n", loc)
}
}
tbl.dirty = true
}
set_cell_alignment :: proc(tbl: ^Table, row, col: int, alignment: Cell_Alignment, loc := #caller_location) {
cell := get_cell(tbl, row, col, loc)
cell.alignment = alignment
tbl.dirty = true
}
format :: proc(tbl: ^Table, _fmt: string, args: ..any, loc := #caller_location) -> string {
context.allocator = tbl.format_allocator
return fmt.aprintf(fmt = _fmt, args = args)
}
header :: proc(tbl: ^Table, values: ..any, loc := #caller_location) {
if (tbl.has_header_row && tbl.nr_rows != 1) || (!tbl.has_header_row && tbl.nr_rows != 0) {
panic("Cannot add headers after rows have been added", loc)
}
if tbl.nr_rows == 0 {
tbl.nr_rows += 1
tbl.has_header_row = true
}
col := tbl.nr_cols
tbl.nr_cols += len(values)
for val in values {
set_cell_value(tbl, header_row(tbl), col, val, loc)
col += 1
}
tbl.dirty = true
}
row :: proc(tbl: ^Table, values: ..any, loc := #caller_location) {
if tbl.nr_cols == 0 {
if len(values) == 0 {
panic("Cannot create row without values unless knowing amount of columns in advance")
} else {
tbl.nr_cols = len(values)
}
}
tbl.nr_rows += 1
for col in 0..<tbl.nr_cols {
val := values[col] if col < len(values) else nil
set_cell_value(tbl, last_row(tbl), col, val)
}
tbl.dirty = true
}
last_row :: proc(tbl: ^Table) -> int {
return tbl.nr_rows - 1
}
header_row :: proc(tbl: ^Table) -> int {
return 0 if tbl.has_header_row else -1
}
first_row :: proc(tbl: ^Table) -> int {
return header_row(tbl)+1 if tbl.has_header_row else 0
}
build :: proc(tbl: ^Table) {
tbl.dirty = false
resize(&tbl.colw, tbl.nr_cols)
mem.zero_slice(tbl.colw[:])
for row in 0..<tbl.nr_rows {
for col in 0..<tbl.nr_cols {
cell := get_cell(tbl, row, col)
if w := len(cell.text) + tbl.lpad + tbl.rpad; w > tbl.colw[col] {
tbl.colw[col] = w
}
}
}
colw_sum := 0
for v in tbl.colw {
colw_sum += v
}
tbl.tblw = max(colw_sum, len(tbl.caption) + tbl.lpad + tbl.rpad)
// Resize columns to match total width of table
remain := tbl.tblw-colw_sum
for col := 0; remain > 0; col = (col + 1) % tbl.nr_cols {
tbl.colw[col] += 1
remain -= 1
}
return
}
write_html_table :: proc(w: io.Writer, tbl: ^Table) {
if tbl.dirty {
build(tbl)
}
io.write_string(w, "<table>\n")
if tbl.caption != "" {
io.write_string(w, "<caption>")
io.write_string(w, tbl.caption)
io.write_string(w, "</caption>\n")
}
align_attribute :: proc(cell: ^Cell) -> string {
switch cell.alignment {
case .Left: return ` align="left"`
case .Center: return ` align="center"`
case .Right: return ` align="right"`
}
unreachable()
}
if tbl.has_header_row {
io.write_string(w, "<thead>\n")
io.write_string(w, " <tr>\n")
for col in 0..<tbl.nr_cols {
cell := get_cell(tbl, header_row(tbl), col)
io.write_string(w, " <th")
io.write_string(w, align_attribute(cell))
io.write_string(w, ">")
io.write_string(w, cell.text)
io.write_string(w, "</th>\n")
}
io.write_string(w, " </tr>\n")
io.write_string(w, "</thead>\n")
}
io.write_string(w, "<tbody>\n")
for row in 0..<tbl.nr_rows {
if tbl.has_header_row && row == header_row(tbl) {
continue
}
io.write_string(w, " <tr>\n")
for col in 0..<tbl.nr_cols {
cell := get_cell(tbl, row, col)
io.write_string(w, " <td")
io.write_string(w, align_attribute(cell))
io.write_string(w, ">")
io.write_string(w, cell.text)
io.write_string(w, "</td>\n")
}
io.write_string(w, " </tr>\n")
}
io.write_string(w, " </tbody>\n")
io.write_string(w, "</table>\n")
}
write_ascii_table :: proc(w: io.Writer, tbl: ^Table) {
if tbl.dirty {
build(tbl)
}
write_caption_separator :: proc(w: io.Writer, tbl: ^Table) {
io.write_byte(w, '+')
write_byte_repeat(w, tbl.tblw + tbl.nr_cols - 1, '-')
io.write_byte(w, '+')
io.write_byte(w, '\n')
}
write_table_separator :: proc(w: io.Writer, tbl: ^Table) {
for col in 0..<tbl.nr_cols {
if col == 0 {
io.write_byte(w, '+')
}
write_byte_repeat(w, tbl.colw[col], '-')
io.write_byte(w, '+')
}
io.write_byte(w, '\n')
}
if tbl.caption != "" {
write_caption_separator(w, tbl)
io.write_byte(w, '|')
write_text_align(w, tbl.tblw - tbl.lpad - tbl.rpad + tbl.nr_cols - 1,
tbl.lpad, tbl.rpad, tbl.caption, .Center)
io.write_byte(w, '|')
io.write_byte(w, '\n')
}
write_table_separator(w, tbl)
for row in 0..<tbl.nr_rows {
for col in 0..<tbl.nr_cols {
if col == 0 {
io.write_byte(w, '|')
}
write_table_cell(w, tbl, row, col)
io.write_byte(w, '|')
}
io.write_byte(w, '\n')
if tbl.has_header_row && row == header_row(tbl) {
write_table_separator(w, tbl)
}
}
write_table_separator(w, tbl)
}
// Renders table according to GitHub Flavored Markdown (GFM) specification
write_markdown_table :: proc(w: io.Writer, tbl: ^Table) {
// NOTE(oskar): Captions or colspans are not supported by GFM as far as I can tell.
if tbl.dirty {
build(tbl)
}
for row in 0..<tbl.nr_rows {
for col in 0..<tbl.nr_cols {
cell := get_cell(tbl, row, col)
if col == 0 {
io.write_byte(w, '|')
}
write_text_align(w, tbl.colw[col] - tbl.lpad - tbl.rpad, tbl.lpad, tbl.rpad, cell.text,
.Center if tbl.has_header_row && row == header_row(tbl) else .Left)
io.write_string(w, "|")
}
io.write_byte(w, '\n')
if tbl.has_header_row && row == header_row(tbl) {
for col in 0..<tbl.nr_cols {
cell := get_cell(tbl, row, col)
if col == 0 {
io.write_byte(w, '|')
}
switch cell.alignment {
case .Left:
io.write_byte(w, ':')
write_byte_repeat(w, max(1, tbl.colw[col]-1), '-')
case .Center:
io.write_byte(w, ':')
write_byte_repeat(w, max(1, tbl.colw[col]-2), '-')
io.write_byte(w, ':')
case .Right:
write_byte_repeat(w, max(1, tbl.colw[col]-1), '-')
io.write_byte(w, ':')
}
io.write_byte(w, '|')
}
io.write_byte(w, '\n')
}
}
}
write_byte_repeat :: proc(w: io.Writer, n: int, b: byte) {
for _ in 0..<n {
io.write_byte(w, b)
}
}
write_table_cell :: proc(w: io.Writer, tbl: ^Table, row, col: int) {
if tbl.dirty {
build(tbl)
}
cell := get_cell(tbl, row, col)
write_text_align(w, tbl.colw[col]-tbl.lpad-tbl.rpad, tbl.lpad, tbl.rpad, cell.text, cell.alignment)
}
write_text_align :: proc(w: io.Writer, colw, lpad, rpad: int, text: string, alignment: Cell_Alignment) {
write_byte_repeat(w, lpad, ' ')
switch alignment {
case .Left:
io.write_string(w, text)
write_byte_repeat(w, colw - len(text), ' ')
case .Center:
pad := colw - len(text)
odd := pad & 1 != 0
write_byte_repeat(w, pad/2, ' ')
io.write_string(w, text)
write_byte_repeat(w, pad/2 + 1 if odd else pad/2, ' ')
case .Right:
write_byte_repeat(w, colw - len(text), ' ')
io.write_string(w, text)
}
write_byte_repeat(w, rpad, ' ')
}
+13
View File
@@ -0,0 +1,13 @@
package text_table
import "core:io"
import "core:os"
import "core:strings"
stdio_writer :: proc() -> io.Writer {
return io.to_writer(os.stream_from_handle(os.stdout))
}
strings_builder_writer :: proc(b: ^strings.Builder) -> io.Writer {
return strings.to_writer(b)
}