force C function definitions

pull/2871/head
Alexander Medvednikov 2019-11-24 06:27:02 +03:00
parent 1f93bb5a9a
commit e9e931fe4a
22 changed files with 227 additions and 84 deletions

View File

@ -19,6 +19,7 @@
+ bring back generics + bring back generics
- bring back forum/blog and vpm - bring back forum/blog and vpm
- wrap up orm - wrap up orm
+ bring back vweb
- fix vorum, migrate to orm - fix vorum, migrate to orm
- wrap up memory management - wrap up memory management
- remove all compiler memory leaks - remove all compiler memory leaks
@ -42,6 +43,6 @@
+ bare metal support + bare metal support
+ inline assembly + inline assembly
+ x64 machine code generation (ELF) + x64 machine code generation (ELF)
- require implicit C.fn definitions, add all missing definitions - require explicit C.fn definitions, add all missing definitions

View File

@ -132,6 +132,7 @@ TODO
print_backtrace() print_backtrace()
#endif #endif
*/ */
free(C.malloc(n))
ptr := C.malloc(n) ptr := C.malloc(n)
if isnil(ptr) { if isnil(ptr) {
panic('malloc($n) failed') panic('malloc($n) failed')

View File

@ -29,6 +29,66 @@ fn C.realpath(byteptr, byteptr) &char
fn C.chmod(byteptr, int)
fn C.printf(byteptr, ...byteptr)
fn C.fputs(byteptr)
fn C.fflush(byteptr) int
// TODO define args in these functions
fn C.fseek() int
fn C.fopen() int
fn C.fwrite() int
fn C.fclose() int
fn C.pclose() int
fn C.system() int
fn C.setenv() int
fn C.unsetenv() int
fn C.access() int
fn C.remove() int
fn C.rmdir() int
fn C.chdir() int
fn C.fread() int
fn C.rewind() int
fn C.stat() int
fn C.rename() int
fn C.fgets() int
fn C.memset() int
fn C.sigemptyset() int
fn C.getcwd() int
fn C.signal() int
fn C.mktime() int
fn C.gettimeofday() int
fn C.sleep() int
fn C.usleep() int
fn C.opendir() voidptr
fn C.closedir() int
fn C.mkdir() int
fn C.srand() int
fn C.atof() int
fn C.tolower() int
fn C.toupper() int
fn C.getchar() int
fn C.strerror() *C.char
fn C.snprintf() int
fn C.fprintf(byteptr, ...byteptr)
fn C.WIFEXITED() bool
fn C.WEXITSTATUS() int
fn C.WIFSIGNALED() bool
fn C.WTERMSIG() int
fn C.DEFAULT_LE() bool
fn C.DEFAULT_EQ() bool
fn C.DEFAULT_GT() bool
fn C.DEFAULT_EQUAL() bool
fn C.DEFAULT_NOT_EQUAL() bool
fn C.DEFAULT_LT() bool
fn C.DEFAULT_GE() bool
fn C.isatty() int
// Windows // Windows
fn C._setmode(int, int) fn C._setmode(int, int)
fn C._fileno(int) int fn C._fileno(int) int
@ -42,3 +102,4 @@ fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumbe
fn C.GetFileAttributesW(lpFileName byteptr) u32 fn C.GetFileAttributesW(lpFileName byteptr) u32
fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lpReserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lpReserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int
fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int
fn C.RemoveDirectory() int

View File

@ -95,6 +95,7 @@ pub fn tos2(s byteptr) string {
} }
} }
// Same as `tos2`, but for char*, to avoid warnings
pub fn tos3(s *C.char) string { pub fn tos3(s *C.char) string {
if s == 0 { if s == 0 {
panic('tos3: nil string') panic('tos3: nil string')

View File

@ -37,6 +37,8 @@ fn (cb &Clipboard) has_ownership() bool {
return false return false
} }
fn C.OSAtomicCompareAndSwapLong()
fn (cb &Clipboard) set_text(text string) bool { fn (cb &Clipboard) set_text(text string) bool {
#NSString *ns_clip; #NSString *ns_clip;
mut ret := false mut ret := false

View File

@ -1266,7 +1266,7 @@ fn replace_generic_type(gen_type string, ti &TypeInst) string {
args_r << replace_generic_type(arg, ti) args_r << replace_generic_type(arg, ti)
} }
mut t := 'fn (' + args_r.join(',') + ')' mut t := 'fn (' + args_r.join(',') + ')'
if ret_t.len > 0 { if ret_t.len > 0 {
t += ' ' + replace_generic_type(ret_t, ti) t += ' ' + replace_generic_type(ret_t, ti)
} }
typ = t typ = t
@ -1379,7 +1379,7 @@ fn (p mut Parser) register_multi_return_stuct(types []string) string {
return typ return typ
} }
// save the tokens for the generic funciton body (between `{}`) // save the tokens for the generic funciton body (between `{}`)
// the function signature isn't saved, it is reconstructed from Fn // the function signature isn't saved, it is reconstructed from Fn
fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) { fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) {
mut cbr_depth := 1 mut cbr_depth := 1

View File

@ -1555,8 +1555,6 @@ fn (p mut Parser) get_const_type(name string, is_ptr bool) string {
} }
fn (p mut Parser) get_c_func_type(name string) string { fn (p mut Parser) get_c_func_type(name string) string {
//p.warn(name + ' ' + p.expected_type)
//}
f := Fn { f := Fn {
name: name name: name
is_c: true is_c: true
@ -1564,15 +1562,15 @@ fn (p mut Parser) get_c_func_type(name string) string {
p.is_c_fn_call = true p.is_c_fn_call = true
p.fn_call(mut f, 0, '', '') p.fn_call(mut f, 0, '', '')
p.is_c_fn_call = false p.is_c_fn_call = false
// Try looking it up. Maybe its defined with "C.fn_name() fn_type", // C functions must be defined with `C.fn_name() fn_type`
// then we know what type it returns
cfn := p.table.find_fn(name) or { cfn := p.table.find_fn(name) or {
// Not Found? Return 'void*' // Is the user trying to do `var := C.foo()` or `bar(C.foo())`
//return 'cvoid' //'void*' // without declaring `foo`?
//if p.expected_type != '' && p.expected_type != 'void' { // Do not allow it.
//p.warn('\n e=$p.expected_type define imported C function with ' + if !name.starts_with('gl') && !name.starts_with('glad') {
//'`fn C.$name([args]) [return_type]`\n') p.error('undefined C function `$f.name`\n' +
//} 'define it with `fn C.$name([args]) [return_type]`')
}
return 'void*' return 'void*'
} }
// println("C fn $name has type $cfn.typ") // println("C fn $name has type $cfn.typ")

View File

@ -89,7 +89,7 @@ pub fn (g mut Gen) generate_elf_footer() {
g.write64_at(file_size, g.file_size_pos+8) g.write64_at(file_size, g.file_size_pos+8)
// Create the binary // Create the binary
f := os.create(g.out_name) or { panic(err) } f := os.create(g.out_name) or { panic(err) }
C.chmod(g.out_name.str, 0775) os.chmod(g.out_name, 0775)
f.write_bytes(g.buf.data, g.buf.len) f.write_bytes(g.buf.data, g.buf.len)
f.close() f.close()
println('x64 elf binary has been successfully generated') println('x64 elf binary has been successfully generated')

View File

@ -8,6 +8,8 @@ module rand
#flag darwin -framework Security #flag darwin -framework Security
fn C.SecRandomCopyBytes() int
pub fn read(bytes_needed int) ?[]byte { pub fn read(bytes_needed int) ?[]byte {
mut buffer := malloc(bytes_needed) mut buffer := malloc(bytes_needed)
status := C.SecRandomCopyBytes(0, bytes_needed, buffer) status := C.SecRandomCopyBytes(0, bytes_needed, buffer)

View File

@ -43,6 +43,8 @@ pub fn get_array<T>(p Params, name string, def T) []T {
return [] return []
} }
fn C.map_set() // TODO remove hack
// TODO: make this a method after generics are fixed. // TODO: make this a method after generics are fixed.
pub fn get_map<T>(p Params, name string, valueTyp T) map[string]T { pub fn get_map<T>(p Params, name string, valueTyp T) map[string]T {
param, _ := p.get_param(name, "") param, _ := p.get_param(name, "")
@ -55,6 +57,7 @@ pub fn get_map<T>(p Params, name string, valueTyp T) map[string]T {
keys = C.new_array_from_c_array_no_alloc(len, len, sizeof(T), param.keys) keys = C.new_array_from_c_array_no_alloc(len, len, sizeof(T), param.keys)
for i, key in keys { for i, key in keys {
//the most simple way to set map value without knowing the typ //the most simple way to set map value without knowing the typ
// TODO remove
C.map_set(&ret, key, param.value + i * sizeof(T)) C.map_set(&ret, key, param.value + i * sizeof(T))
} }
} }

View File

@ -34,6 +34,10 @@ import (
#include "ft2build.h" #include "ft2build.h"
#include FT_FREETYPE_H #include FT_FREETYPE_H
fn C.FT_Init_FreeType() voidptr
fn C.FT_New_Face() voidptr
fn C.FT_Set_Pixel_Sizes()
const ( const (

View File

@ -153,6 +153,11 @@ pub fn (s Shader) use() {
gl.use_program(s.program_id) gl.use_program(s.program_id)
} }
fn C.glGetUniformLocation() int
fn C.glUniformMatrix4fv()
fn C.glUniform1i()
fn C.glUniform3f()
pub fn (s Shader) uni_location(key string) int { pub fn (s Shader) uni_location(key string) int {
return C.glGetUniformLocation(s.program_id, key.str) return C.glGetUniformLocation(s.program_id, key.str)
} }

View File

@ -4,7 +4,7 @@
module http module http
import strings import strings
// On linux, prefer a localy build openssl, because it is // On linux, prefer a localy build openssl, because it is
// much more likely for it to be newer, than the system // much more likely for it to be newer, than the system
@ -24,67 +24,87 @@ import strings
#include <openssl/ssl.h> #include <openssl/ssl.h>
struct C.SSL { struct C.SSL {
} }
fn C.SSL_library_init()
fn C.TLSv1_2_method() voidptr
fn C.SSL_CTX_set_options()
fn C.SSL_CTX_new() voidptr
fn C.SSL_CTX_set_verify_depth()
fn C.SSL_CTX_load_verify_locations() int
fn C.BIO_new_ssl_connect() voidptr
fn C.BIO_set_conn_hostname() int
fn C.BIO_get_ssl()
fn C.SSL_set_cipher_list() int
fn C.BIO_do_connect() int
fn C.BIO_do_handshake() int
fn C.SSL_get_peer_certificate() int
fn C.SSL_get_verify_result() int
fn C.SSL_set_tlsext_host_name() int
fn C.BIO_puts()
fn C.BIO_read()
fn C.BIO_free_all()
fn C.SSL_CTX_free()
fn init() int { fn init() int {
C.SSL_library_init() C.SSL_library_init()
return 1 return 1
} }
fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response {
//ssl_method := C.SSLv23_method() //ssl_method := C.SSLv23_method()
ssl_method := C.TLSv1_2_method() ssl_method := C.TLSv1_2_method()
if isnil(method) { if isnil(method) {
} }
ctx := C.SSL_CTX_new(ssl_method) ctx := C.SSL_CTX_new(ssl_method)
if isnil(ctx) { if isnil(ctx) {
} }
C.SSL_CTX_set_verify_depth(ctx, 4) C.SSL_CTX_set_verify_depth(ctx, 4)
flags := C.SSL_OP_NO_SSLv2 | C.SSL_OP_NO_SSLv3 | C.SSL_OP_NO_COMPRESSION flags := C.SSL_OP_NO_SSLv2 | C.SSL_OP_NO_SSLv3 | C.SSL_OP_NO_COMPRESSION
C.SSL_CTX_set_options(ctx, flags) C.SSL_CTX_set_options(ctx, flags)
mut res := C.SSL_CTX_load_verify_locations(ctx, 'random-org-chain.pem', 0) mut res := C.SSL_CTX_load_verify_locations(ctx, 'random-org-chain.pem', 0)
if res != 1 { if res != 1 {
} }
web := C.BIO_new_ssl_connect(ctx) web := C.BIO_new_ssl_connect(ctx)
if isnil(ctx) { if isnil(ctx) {
} }
addr := host_name + ':' + port.str() addr := host_name + ':' + port.str()
res = C.BIO_set_conn_hostname(web, addr.str) res = C.BIO_set_conn_hostname(web, addr.str)
if res != 1 { if res != 1 {
} }
ssl := &C.SSL{!} ssl := &C.SSL{!}
C.BIO_get_ssl(web, &ssl) C.BIO_get_ssl(web, &ssl)
if isnil(ssl) { if isnil(ssl) {
} }
preferred_ciphers := 'HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4' preferred_ciphers := 'HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4'
res = C.SSL_set_cipher_list(ssl, preferred_ciphers.str) res = C.SSL_set_cipher_list(ssl, preferred_ciphers.str)
if res != 1 { if res != 1 {
} }
res = C.SSL_set_tlsext_host_name(ssl, host_name.str) res = C.SSL_set_tlsext_host_name(ssl, host_name.str)
res = C.BIO_do_connect(web) res = C.BIO_do_connect(web)
res = C.BIO_do_handshake(web) res = C.BIO_do_handshake(web)
cert := C.SSL_get_peer_certificate(ssl) cert := C.SSL_get_peer_certificate(ssl)
res = C.SSL_get_verify_result(ssl) res = C.SSL_get_verify_result(ssl)
/////// ///////
s := req.build_request_headers(method, host_name, path) s := req.build_request_headers(method, host_name, path)
C.BIO_puts(web, s.str) C.BIO_puts(web, s.str)
mut sb := strings.new_builder(100) mut sb := strings.new_builder(100)
for { for {
buff := [1536]byte buff := [1536]byte
len := int(C.BIO_read(web, buff, 1536) ) len := int(C.BIO_read(web, buff, 1536) )
if len > 0 { if len > 0 {
sb.write(tos(buff, len)) sb.write(tos(buff, len))
} }
else { else {
break break
} }
} }
if !isnil(web) { if !isnil(web) {
C.BIO_free_all(web) C.BIO_free_all(web)
} }
if !isnil(ctx) { if !isnil(ctx) {
C.SSL_CTX_free(ctx) C.SSL_CTX_free(ctx)
} }
return parse_response(sb.str()) return parse_response(sb.str())

View File

@ -97,6 +97,13 @@ fn jsdecode_string(root &C.cJSON) string {
return tos_clone(root.valuestring)// , _strlen(root.valuestring)) return tos_clone(root.valuestring)// , _strlen(root.valuestring))
} }
fn C.cJSON_IsTrue() bool
fn C.cJSON_CreateNumber() &C.cJSON
fn C.cJSON_CreateBool() &C.cJSON
fn C.cJSON_CreateString() &C.cJSON
fn C.cJSON_Parse() &C.cJSON
fn C.cJSON_PrintUnformatted() byteptr
fn jsdecode_bool(root &C.cJSON) bool { fn jsdecode_bool(root &C.cJSON) bool {
if isnil(root) { if isnil(root) {
return false return false

View File

@ -28,6 +28,7 @@ fn C.lgamma(x f64) f64
fn C.pow(x f64, y f64) f64 fn C.pow(x f64, y f64) f64
fn C.round(x f64) f64 fn C.round(x f64) f64
fn C.sin(x f64) f64 fn C.sin(x f64) f64
fn C.sinh(x f64) f64
fn C.sqrt(x f64) f64 fn C.sqrt(x f64) f64
fn C.tgamma(x f64) f64 fn C.tgamma(x f64) f64
fn C.tan(x f64) f64 fn C.tan(x f64) f64

View File

@ -1,6 +1,8 @@
module net module net
// hostname returns the host name reported by the kernel. fn C.gethostname() int
// hostname returns the host name reported by the kernel.
pub fn hostname() ?string { pub fn hostname() ?string {
mut name := [256]byte mut name := [256]byte
// https://www.ietf.org/rfc/rfc1035.txt // https://www.ietf.org/rfc/rfc1035.txt

View File

@ -36,15 +36,31 @@ mut:
} }
struct C.sockaddr_storage {} struct C.sockaddr_storage {}
fn C.socket() int
fn C.setsockopt() int
fn C.htonl() int
fn C.htons() int
fn C.bind() int
fn C.listen() int
fn C.accept() int
fn C.getaddrinfo() int
fn C.connect() int
fn C.send() int
fn C.recv() int
fn C.read() int
fn C.shutdown() int
fn C.close() int
fn C.ntohs() int
fn C.getsockname() int
// create socket // create socket
pub fn socket(family int, _type int, proto int) ?Socket { pub fn new_socket(family int, _type int, proto int) ?Socket {
sockfd := C.socket(family, _type, proto) sockfd := C.socket(family, _type, proto)
one:=1 one:=1
// This is needed so that there are no problems with reusing the // This is needed so that there are no problems with reusing the
// same port after the application exits. // same port after the application exits.
C.setsockopt(sockfd, C.SOL_SOCKET, C.SO_REUSEADDR, &one, sizeof(int)) C.setsockopt(sockfd, C.SOL_SOCKET, C.SO_REUSEADDR, &one, 4)//sizeof(int))
if sockfd == 0 { if sockfd == 0 {
return error('net.socket: failed') return error('net.socket: failed')
} }
@ -58,16 +74,16 @@ pub fn socket(family int, _type int, proto int) ?Socket {
} }
pub fn socket_udp() ?Socket { pub fn socket_udp() ?Socket {
return socket(C.AF_INET, C.SOCK_DGRAM, C.IPPROTO_UDP) return new_socket(C.AF_INET, C.SOCK_DGRAM, C.IPPROTO_UDP)
} }
// set socket options // set socket options
pub fn (s Socket) setsockopt(level int, optname int, optvalue &int) ?int { pub fn (s Socket) setsockopt(level int, optname int, optvalue &int) ?int {
res := C.setsockopt(s.sockfd, level, optname, optvalue, C.sizeof(optvalue)) res := C.setsockopt(s.sockfd, level, optname, optvalue, sizeof(int))
if res < 0 { if res < 0 {
return error('net.setsocketopt: failed with $res') return error('net.setsocketopt: failed with $res')
} }
return int(res) return res
} }
// bind socket to port // bind socket to port
@ -77,7 +93,7 @@ pub fn (s Socket) bind(port int) ?int {
addr.sin_port = C.htons(port) addr.sin_port = C.htons(port)
addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY) addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY)
size := 16 // sizeof(C.sockaddr_in) size := 16 // sizeof(C.sockaddr_in)
res := int(C.bind(s.sockfd, &addr, size)) res := C.bind(s.sockfd, &addr, size)
if res < 0 { if res < 0 {
return error('net.bind: failed with $res') return error('net.bind: failed with $res')
} }
@ -87,7 +103,7 @@ pub fn (s Socket) bind(port int) ?int {
// put socket into passive mode and wait to receive // put socket into passive mode and wait to receive
pub fn (s Socket) listen() ?int { pub fn (s Socket) listen() ?int {
backlog := 128 backlog := 128
res := int(C.listen(s.sockfd, backlog)) res := C.listen(s.sockfd, backlog)
if res < 0 { if res < 0 {
return error('net.listen: failed with $res') return error('net.listen: failed with $res')
} }
@ -107,7 +123,7 @@ pub fn (s Socket) listen_backlog(backlog int) ?int {
if res < 0 { if res < 0 {
return error('net.listen_backlog: failed with $res') return error('net.listen_backlog: failed with $res')
} }
return int(res) return res
} }
// helper method to create, bind, and listen given port number // helper method to create, bind, and listen given port number
@ -115,7 +131,7 @@ pub fn listen(port int) ?Socket {
$if debug { $if debug {
println('net.listen($port)') println('net.listen($port)')
} }
s := socket(C.AF_INET, C.SOCK_STREAM, 0) or { s := new_socket(C.AF_INET, C.SOCK_STREAM, 0) or {
return error(err) return error(err)
} }
bind_res := s.bind(port) or { bind_res := s.bind(port) or {
@ -167,17 +183,17 @@ pub fn (s Socket) connect(address string, port int) ?int {
error_message := os.get_error_msg(net.error_code()) error_message := os.get_error_msg(net.error_code())
return error('net.connect: getaddrinfo failed "$error_message"') return error('net.connect: getaddrinfo failed "$error_message"')
} }
res := int(C.connect(s.sockfd, info.ai_addr, info.ai_addrlen)) res := C.connect(s.sockfd, info.ai_addr, info.ai_addrlen)
if res < 0 { if res < 0 {
error_message := os.get_error_msg(net.error_code()) error_message := os.get_error_msg(net.error_code())
return error('net.connect: connect failed "$error_message"') return error('net.connect: connect failed "$error_message"')
} }
return int(res) return res
} }
// helper method to create socket and connect // helper method to create socket and connect
pub fn dial(address string, port int) ?Socket { pub fn dial(address string, port int) ?Socket {
s := socket(C.AF_INET, C.SOCK_STREAM, 0) or { s := new_socket(C.AF_INET, C.SOCK_STREAM, 0) or {
return error(err) return error(err)
} }
res := s.connect(address, port) or { res := s.connect(address, port) or {
@ -188,7 +204,7 @@ pub fn dial(address string, port int) ?Socket {
// send string data to socket // send string data to socket
pub fn (s Socket) send(buf byteptr, len int) ?int { pub fn (s Socket) send(buf byteptr, len int) ?int {
res := int( C.send(s.sockfd, buf, len, MSG_NOSIGNAL) ) res := C.send(s.sockfd, buf, len, MSG_NOSIGNAL)
if res < 0 { if res < 0 {
return error('net.send: failed with $res') return error('net.send: failed with $res')
} }
@ -198,18 +214,18 @@ pub fn (s Socket) send(buf byteptr, len int) ?int {
// receive string data from socket // receive string data from socket
pub fn (s Socket) recv(bufsize int) (byteptr, int) { pub fn (s Socket) recv(bufsize int) (byteptr, int) {
buf := malloc(bufsize) buf := malloc(bufsize)
res := int( C.recv(s.sockfd, buf, bufsize, 0) ) res := C.recv(s.sockfd, buf, bufsize, 0)
return buf, res return buf, res
} }
// TODO: remove cread/2 and crecv/2 when the Go net interface is done // TODO: remove cread/2 and crecv/2 when the Go net interface is done
pub fn (s Socket) cread( buffer byteptr, buffersize int ) int { pub fn (s Socket) cread( buffer byteptr, buffersize int ) int {
return int( C.read(s.sockfd, buffer, buffersize) ) return C.read(s.sockfd, buffer, buffersize)
} }
// Receive a message from the socket, and place it in a preallocated buffer buf, // Receive a message from the socket, and place it in a preallocated buffer buf,
// with maximum message size bufsize. Returns the length of the received message. // with maximum message size bufsize. Returns the length of the received message.
pub fn (s Socket) crecv( buffer byteptr, buffersize int ) int { pub fn (s Socket) crecv( buffer byteptr, buffersize int ) int {
return int( C.recv(s.sockfd, buffer, buffersize, 0) ) return C.recv(s.sockfd, buffer, buffersize, 0)
} }
// shutdown and close socket // shutdown and close socket
@ -250,7 +266,7 @@ pub const (
// write - write a string with CRLF after it over the socket s // write - write a string with CRLF after it over the socket s
pub fn (s Socket) write(str string) ?int { pub fn (s Socket) write(str string) ?int {
line := '$str$CRLF' line := '$str$CRLF'
res := int( C.send(s.sockfd, line.str, line.len, MSG_NOSIGNAL) ) res := C.send(s.sockfd, line.str, line.len, MSG_NOSIGNAL)
if res < 0 { return error('net.write: failed with $res') } if res < 0 { return error('net.write: failed with $res') }
return res return res
} }
@ -299,6 +315,6 @@ pub fn (s Socket) read_line() string {
pub fn (s Socket) get_port() int { pub fn (s Socket) get_port() int {
mut addr := C.sockaddr_in {} mut addr := C.sockaddr_in {}
size := 16 // sizeof(sockaddr_in) size := 16 // sizeof(sockaddr_in)
sockname_res := C.getsockname(s.sockfd, &addr, &size) C.getsockname(s.sockfd, &addr, &size)
return int(C.ntohs(addr.sin_port)) return C.ntohs(addr.sin_port)
} }

View File

@ -1026,3 +1026,8 @@ pub fn tmpdir() string {
} }
return path return path
} }
pub fn chmod(path string, mode int) {
C.chmod(path.str, mode)
}

View File

@ -18,11 +18,11 @@ pub fn init_os_args(argc int, argv &byteptr) []string {
// get_error_msg return error code representation in string. // get_error_msg return error code representation in string.
pub fn get_error_msg(code int) string { pub fn get_error_msg(code int) string {
_ptr_text := C.strerror(code) // voidptr? ptr_text := C.strerror(code) // voidptr?
if _ptr_text == 0 { if ptr_text == 0 {
return '' return ''
} }
return tos(_ptr_text, vstrlen(_ptr_text)) return tos3(ptr_text)
} }
pub fn ls(path string) ?[]string { pub fn ls(path string) ?[]string {

View File

@ -34,6 +34,11 @@ pub fn (db DB) q_int(query string) int {
} }
fn C.sqlite3_column_text(voidptr, int) byteptr fn C.sqlite3_column_text(voidptr, int) byteptr
fn C.sqlite3_column_int(voidptr, int) int
fn C.sqlite3_open()
fn C.sqlite3_step() int
fn C.sqlite3_prepare_v2()
fn C.sqlite3_finalize()
pub fn (db DB) q_string(query string) string { pub fn (db DB) q_string(query string) string {
stmt := &C.sqlite3_stmt{!} stmt := &C.sqlite3_stmt{!}

View File

@ -21,6 +21,10 @@ mut:
ext string ext string
} }
fn C.stbi_load() voidptr
fn C.stbi_image_free()
fn C.stbi_set_flip_vertically_on_load()
pub fn load(path string) Image { pub fn load(path string) Image {
ext := path.all_after('.') ext := path.all_after('.')
mut res := Image { mut res := Image {

View File

@ -6,6 +6,11 @@ module sync
#include <pthread.h> #include <pthread.h>
fn C.pthread_mutex_init()
fn C.pthread_mutex_lock()
fn C.pthread_mutex_unlock()
//[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function. //[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
pub struct Mutex { pub struct Mutex {
mutex C.pthread_mutex_t mutex C.pthread_mutex_t