mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: bare metal support (fix -freestanding
) (#9624)
This commit is contained in:
parent
711e309eef
commit
14434cc86a
@ -80,7 +80,7 @@ fn main() {
|
||||
verror(err.msg)
|
||||
return
|
||||
}
|
||||
if is_atty(0) == 0 && files.len == 0 {
|
||||
if os.is_atty(0) == 0 && files.len == 0 {
|
||||
foptions.format_pipe()
|
||||
exit(0)
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ mut:
|
||||
vstartup_lines []string // lines in the `VSTARTUP` file
|
||||
}
|
||||
|
||||
const is_stdin_a_pipe = (is_atty(0) == 0)
|
||||
const is_stdin_a_pipe = (os.is_atty(0) == 0)
|
||||
|
||||
const vexe = os.getenv('VEXE')
|
||||
|
||||
|
@ -35,6 +35,7 @@ const (
|
||||
'vlib/v/tests/generics_test.v', /* multi_generic_args<Foo<int>, Foo<int> >(...) becomes .... Foo<int>>(...) which does not parse */
|
||||
'vlib/v/tests/string_interpolation_test.v' /* TODO byteptr: &byte.str() behaves differently than byteptr.str() */,
|
||||
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
||||
'vlib/v/gen/c/cheaders.v' /* the preprocessor directives are formated to the V standard, even though they are in a string literal */,
|
||||
]
|
||||
vfmt_verify_list = [
|
||||
'cmd/',
|
||||
|
@ -15,12 +15,12 @@ const (
|
||||
'vlib/builtin/js/jsfns_node.js.v',
|
||||
'vlib/builtin/js/jsfns.js.v',
|
||||
'vlib/builtin/js/jsfns_browser.js.v',
|
||||
// error: expr(): bad token `asm`, on `asm {}`
|
||||
'vlib/builtin/bare/linuxsys_bare.v',
|
||||
// total chaos (duplicated code several times) in array_eq_test.v
|
||||
'vlib/builtin/array_eq_test.v',
|
||||
// the fn args are removed, then `cb fn (picohttpparser.Request, mut picohttpparser.Response)` can not be reparsed
|
||||
'vlib/picoev/picoev.v',
|
||||
// the preprocessor directives are formated to the V standard, even though they are in a string literal
|
||||
'vlib/v/gen/c/cheaders.v',
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -24,6 +24,47 @@ see also `v help build`.
|
||||
Build the executable without dependency on libc.
|
||||
Supported only on `linux` targets currently.
|
||||
|
||||
-bare-builtin-dir <bare-builtin-dir>
|
||||
Use with `-freestanding`. This specifies the directory to the
|
||||
implementation of some basic builtin functions. The list is as follows:
|
||||
memcpy(dest &byte, src &byte, n int) &byte
|
||||
Moves n bytes from dest to src, and returns dest
|
||||
[export: 'malloc']
|
||||
__malloc(n int) &byte
|
||||
Allocates n bytes of memory and returns the pointer to the first byte
|
||||
strlen(s &byte) int
|
||||
Returns the amount of bytes until the first `0`, starting at s
|
||||
realloc(old_area &byte, new_size int) &byte
|
||||
Allocates a new area of size new_size, copies old_area
|
||||
to the new area, and returns a pointer to the new area.
|
||||
memset(s &byte, c int, n int) &byte
|
||||
Sets n bytes starting at s to c (c is casted to a char)
|
||||
and returns s.
|
||||
memmove(dest &byte, src &byte, n int) &byte
|
||||
Like memcpy, but guaranteed to work if dest and src overlap.
|
||||
[export: 'calloc']
|
||||
__calloc(nmemb int, size int) &byte
|
||||
Like malloc, but sets all the bytes to `0` first.
|
||||
getchar() int
|
||||
Read one character from stdin and return it.
|
||||
memcmp(a &byte, b &byte, n int) int
|
||||
Compare two buffers of length n. If a and b are equal, return 0.
|
||||
Otherwise, return the difference between the first different letter.
|
||||
[export: 'free']
|
||||
__free(ptr &byte)
|
||||
Free the block of memory ptr allocated by malloc.
|
||||
vsprintf(str &char, format &char, ap va_list) int
|
||||
See `man vsprintf`.
|
||||
vsnprintf(str &char, size int, format &char, ap va_list) int
|
||||
See `man vsnprintf`.
|
||||
bare_print(buf &byte, len u64)
|
||||
Print len charecters from the buffer pointed to by buf to stdout.
|
||||
bare_eprint(buf &byte, len u64)
|
||||
Print len charecters from the buffer pointed to by buf to stderr.
|
||||
|
||||
The module decleration should be `builtin`. The default linux
|
||||
implementation can be found in `vlib/builtin/linux_bare`.
|
||||
|
||||
-os <os>, -target-os <os>
|
||||
Change the target OS that V tries to compile for.
|
||||
By default, the target OS is the host system.
|
||||
|
@ -58,7 +58,7 @@ fn main() {
|
||||
if args.len == 0 || args[0] in ['-', 'repl'] {
|
||||
// Running `./v` without args launches repl
|
||||
if args.len == 0 {
|
||||
if is_atty(0) != 0 {
|
||||
if os.is_atty(0) != 0 {
|
||||
println('Welcome to the V REPL (for help with V itself, type `exit`, then run `v help`).')
|
||||
} else {
|
||||
mut args_and_flags := util.join_env_vflags_and_os_args()[1..].clone()
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Binary Search Tree example by @SleepyRoy
|
||||
|
||||
// TODO: make Node.value generic once it's robust enough
|
||||
// TODO: `return match` instead of returns everywhere inside match
|
||||
// TODO: `return match` instead of returns everywhere inside match
|
||||
|
||||
struct Empty {}
|
||||
|
||||
@ -121,22 +121,46 @@ fn delete(tree Tree, x f64) Tree {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut tree := Tree(Empty{})
|
||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in input {
|
||||
tree = insert(tree, i)
|
||||
}
|
||||
println('[1] after insertion tree size is ${size(tree)}') // 11
|
||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del {
|
||||
tree = delete(tree, i)
|
||||
}
|
||||
print('[2] after deletion tree size is ${size(tree)}, ') // 7
|
||||
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in input {
|
||||
if !search(tree, i) {
|
||||
print('$i ')
|
||||
$if !freestanding {
|
||||
mut tree := Tree(Empty{})
|
||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in input {
|
||||
tree = insert(tree, i)
|
||||
}
|
||||
println('[1] after insertion tree size is ${size(tree)}') // 11
|
||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del {
|
||||
tree = delete(tree, i)
|
||||
}
|
||||
print('[2] after deletion tree size is ${size(tree)}, ') // 7
|
||||
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in input {
|
||||
if !search(tree, i) {
|
||||
print('$i ')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
} $else {
|
||||
mut tree := Tree(Empty{})
|
||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in input {
|
||||
tree = insert(tree, i)
|
||||
}
|
||||
print('[1] after insertion tree size is ') // 11
|
||||
println(size(tree))
|
||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del {
|
||||
tree = delete(tree, i)
|
||||
}
|
||||
print('[2] after deletion tree size is ') // 7
|
||||
print(size(tree))
|
||||
print(', and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in input {
|
||||
if !search(tree, i) {
|
||||
print(i)
|
||||
print(' ')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
}
|
||||
println('')
|
||||
}
|
||||
|
@ -136,7 +136,11 @@ pub fn (a array) repeat(count int) array {
|
||||
|
||||
// sort_with_compare sorts array in-place using given `compare` function as comparator.
|
||||
pub fn (mut a array) sort_with_compare(compare voidptr) {
|
||||
C.qsort(mut a.data, a.len, a.element_size, compare)
|
||||
$if freestanding {
|
||||
panic('sort does not work with -freestanding')
|
||||
} $else {
|
||||
C.qsort(mut a.data, a.len, a.element_size, compare)
|
||||
}
|
||||
}
|
||||
|
||||
// insert inserts a value in the array at index `i`
|
||||
|
@ -1,5 +0,0 @@
|
||||
module builtin
|
||||
|
||||
struct string {
|
||||
len int
|
||||
}
|
@ -18,12 +18,17 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||
// module is less likely to change than function, etc...
|
||||
// During edits, the line number will change most frequently,
|
||||
// so it is last
|
||||
eprintln('================ V panic ================')
|
||||
eprintln(' module: $mod')
|
||||
eprintln(' function: ${fn_name}()')
|
||||
eprintln(' message: $s')
|
||||
eprintln(' file: $file:$line_no')
|
||||
eprintln('=========================================')
|
||||
$if !freestanding {
|
||||
eprintln('================ V panic ================')
|
||||
eprintln(' module: $mod')
|
||||
eprintln(' function: ${fn_name}()')
|
||||
eprintln(' message: $s')
|
||||
eprintln(' file: $file:$line_no')
|
||||
eprintln('=========================================')
|
||||
} $else {
|
||||
eprint('V panic: ')
|
||||
eprintln(s)
|
||||
}
|
||||
$if exit_after_panic_message ? {
|
||||
C.exit(1)
|
||||
} $else {
|
||||
@ -38,7 +43,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||
}
|
||||
C.exit(1)
|
||||
}
|
||||
print_backtrace_skipping_top_frames(1)
|
||||
$if !freestanding {
|
||||
print_backtrace_skipping_top_frames(1)
|
||||
}
|
||||
$if panics_break_into_debugger ? {
|
||||
break_if_debugger_attached()
|
||||
}
|
||||
@ -54,7 +61,8 @@ pub fn panic_optional_not_set(s string) {
|
||||
// panic prints a nice error message, then exits the process with exit code of 1.
|
||||
// It also shows a backtrace on most platforms.
|
||||
pub fn panic(s string) {
|
||||
eprintln('V panic: $s')
|
||||
eprint('V panic: ')
|
||||
eprintln(s)
|
||||
$if exit_after_panic_message ? {
|
||||
C.exit(1)
|
||||
} $else {
|
||||
@ -69,7 +77,9 @@ pub fn panic(s string) {
|
||||
}
|
||||
C.exit(1)
|
||||
}
|
||||
print_backtrace_skipping_top_frames(1)
|
||||
$if !freestanding {
|
||||
print_backtrace_skipping_top_frames(1)
|
||||
}
|
||||
$if panics_break_into_debugger ? {
|
||||
break_if_debugger_attached()
|
||||
}
|
||||
@ -80,14 +90,13 @@ pub fn panic(s string) {
|
||||
|
||||
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
||||
pub fn eprintln(s string) {
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
// eprintln is used in panics, so it should not fail at all
|
||||
$if android {
|
||||
$if freestanding {
|
||||
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||
if s.str == 0 {
|
||||
C.fprintf(C.stderr, c'eprintln(NIL)\n')
|
||||
bare_eprint(c'eprintln(NIL)\n', 14)
|
||||
} else {
|
||||
C.fprintf(C.stderr, c'%.*s\n', s.len, s.str)
|
||||
bare_eprint(s.str, u64(s.len))
|
||||
bare_eprint(c'\n', 1)
|
||||
}
|
||||
} $else $if ios {
|
||||
if s.str == 0 {
|
||||
@ -96,25 +105,35 @@ pub fn eprintln(s string) {
|
||||
C.WrappedNSLog(s.str)
|
||||
}
|
||||
} $else {
|
||||
if s.str == 0 {
|
||||
C.write(2, c'eprintln(NIL)\n', 14)
|
||||
} else {
|
||||
C.write(2, s.str, s.len)
|
||||
C.write(2, c'\n', 1)
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
// eprintln is used in panics, so it should not fail at all
|
||||
$if android {
|
||||
if s.str == 0 {
|
||||
C.fprintf(C.stderr, c'eprintln(NIL)\n')
|
||||
} else {
|
||||
C.fprintf(C.stderr, c'%.*s\n', s.len, s.str)
|
||||
}
|
||||
} $else {
|
||||
if s.str == 0 {
|
||||
C.write(2, c'eprintln(NIL)\n', 14)
|
||||
} else {
|
||||
C.write(2, s.str, s.len)
|
||||
C.write(2, c'\n', 1)
|
||||
}
|
||||
}
|
||||
C.fflush(C.stderr)
|
||||
}
|
||||
C.fflush(C.stderr)
|
||||
}
|
||||
|
||||
// eprint prints a message to stderr. Both stderr and stdout are flushed.
|
||||
pub fn eprint(s string) {
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
$if android {
|
||||
$if freestanding {
|
||||
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||
if s.str == 0 {
|
||||
C.fprintf(C.stderr, c'eprint(NIL)')
|
||||
bare_eprint(c'eprint(NIL)\n', 12)
|
||||
} else {
|
||||
C.fprintf(C.stderr, c'%.*s', s.len, s.str)
|
||||
bare_eprint(s.str, u64(s.len))
|
||||
}
|
||||
} $else $if ios {
|
||||
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
||||
@ -124,13 +143,23 @@ pub fn eprint(s string) {
|
||||
C.WrappedNSLog(s.str)
|
||||
}
|
||||
} $else {
|
||||
if s.str == 0 {
|
||||
C.write(2, c'eprint(NIL)', 11)
|
||||
} else {
|
||||
C.write(2, s.str, s.len)
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
$if android {
|
||||
if s.str == 0 {
|
||||
C.fprintf(C.stderr, c'eprint(NIL)')
|
||||
} else {
|
||||
C.fprintf(C.stderr, c'%.*s', s.len, s.str)
|
||||
}
|
||||
} $else {
|
||||
if s.str == 0 {
|
||||
C.write(2, c'eprint(NIL)', 11)
|
||||
} else {
|
||||
C.write(2, s.str, s.len)
|
||||
}
|
||||
}
|
||||
C.fflush(C.stderr)
|
||||
}
|
||||
C.fflush(C.stderr)
|
||||
}
|
||||
|
||||
// print prints a message to stdout. Unlike `println` stdout is not automatically flushed.
|
||||
@ -141,6 +170,8 @@ pub fn print(s string) {
|
||||
} $else $if ios {
|
||||
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
||||
C.WrappedNSLog(s.str)
|
||||
} $else $if freestanding {
|
||||
bare_print(s.str, u64(s.len))
|
||||
} $else {
|
||||
C.write(1, s.str, s.len)
|
||||
}
|
||||
@ -160,6 +191,9 @@ pub fn println(s string) {
|
||||
C.fprintf(C.stdout, c'println(NIL)\n')
|
||||
} $else $if ios {
|
||||
C.WrappedNSLog(c'println(NIL)')
|
||||
} $else $if freestanding {
|
||||
bare_print(s.str, u64(s.len))
|
||||
bare_print(c'println(NIL)\n', 13)
|
||||
} $else {
|
||||
C.write(1, c'println(NIL)\n', 13)
|
||||
}
|
||||
@ -169,6 +203,9 @@ pub fn println(s string) {
|
||||
C.fprintf(C.stdout, c'%.*s\n', s.len, s.str)
|
||||
} $else $if ios {
|
||||
C.WrappedNSLog(s.str)
|
||||
} $else $if freestanding {
|
||||
bare_print(s.str, u64(s.len))
|
||||
bare_print(c'\n', 1)
|
||||
} $else {
|
||||
C.write(1, s.str, s.len)
|
||||
C.write(1, c'\n', 1)
|
||||
@ -205,6 +242,14 @@ pub fn malloc(n int) &byte {
|
||||
unsafe {
|
||||
res = C.GC_MALLOC(n)
|
||||
}
|
||||
} $else $if freestanding {
|
||||
mut e := Errno{}
|
||||
res, e = mm_alloc(u64(n))
|
||||
if e != .enoerror {
|
||||
eprint('malloc() failed: ')
|
||||
eprintln(e.str())
|
||||
panic('malloc() failed')
|
||||
}
|
||||
} $else {
|
||||
res = unsafe { C.malloc(n) }
|
||||
}
|
||||
@ -365,18 +410,6 @@ pub fn memdup(src voidptr, sz int) voidptr {
|
||||
}
|
||||
}
|
||||
|
||||
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
||||
pub fn is_atty(fd int) int {
|
||||
$if windows {
|
||||
mut mode := u32(0)
|
||||
osfh := voidptr(C._get_osfhandle(fd))
|
||||
C.GetConsoleMode(osfh, voidptr(&mode))
|
||||
return int(mode)
|
||||
} $else {
|
||||
return C.isatty(fd)
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn v_fixed_index(i int, len int) int {
|
||||
$if !no_bounds_checking ? {
|
||||
|
@ -13,6 +13,12 @@ pub fn isnil(v voidptr) bool {
|
||||
return v == 0
|
||||
}
|
||||
|
||||
[deprecated: 'use os.is_atty(x) instead']
|
||||
pub fn is_atty(fd int) int {
|
||||
panic('use os.is_atty(x) instead')
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
fn on_panic(f fn(int)int) {
|
||||
// TODO
|
||||
@ -26,7 +32,9 @@ pub fn print_backtrace() {
|
||||
// 1 frame for print_backtrace itself
|
||||
// ... print the rest of the backtrace frames ...
|
||||
// => top 2 frames should be skipped, since they will not be informative to the developer
|
||||
print_backtrace_skipping_top_frames(2)
|
||||
$if !freestanding {
|
||||
print_backtrace_skipping_top_frames(2)
|
||||
}
|
||||
}
|
||||
|
||||
struct VCastTypeIndexName {
|
||||
|
@ -85,55 +85,57 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||
$if no_backtrace ? {
|
||||
return false
|
||||
} $else {
|
||||
$if tinyc {
|
||||
C.tcc_backtrace(c'Backtrace')
|
||||
return false
|
||||
}
|
||||
buffer := [100]voidptr{}
|
||||
nr_ptrs := C.backtrace(&buffer[0], 100)
|
||||
if nr_ptrs < 2 {
|
||||
eprintln('C.backtrace returned less than 2 frames')
|
||||
return false
|
||||
}
|
||||
nr_actual_frames := nr_ptrs - skipframes
|
||||
mut sframes := []string{}
|
||||
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
for i in 0 .. nr_actual_frames {
|
||||
sframes << unsafe { tos2(&byte(csymbols[i])) }
|
||||
}
|
||||
for sframe in sframes {
|
||||
executable := sframe.all_before('(')
|
||||
addr := sframe.all_after('[').all_before(']')
|
||||
beforeaddr := sframe.all_before('[')
|
||||
cmd := 'addr2line -e $executable $addr'
|
||||
// taken from os, to avoid depending on the os module inside builtin.v
|
||||
f := C.popen(&char(cmd.str), c'r')
|
||||
if isnil(f) {
|
||||
eprintln(sframe)
|
||||
continue
|
||||
$if !freestanding {
|
||||
$if tinyc {
|
||||
C.tcc_backtrace(c'Backtrace')
|
||||
return false
|
||||
}
|
||||
buf := [1000]byte{}
|
||||
mut output := ''
|
||||
unsafe {
|
||||
bp := &buf[0]
|
||||
for C.fgets(&char(bp), 1000, f) != 0 {
|
||||
output += tos(bp, vstrlen(bp))
|
||||
buffer := [100]voidptr{}
|
||||
nr_ptrs := C.backtrace(&buffer[0], 100)
|
||||
if nr_ptrs < 2 {
|
||||
eprintln('C.backtrace returned less than 2 frames')
|
||||
return false
|
||||
}
|
||||
nr_actual_frames := nr_ptrs - skipframes
|
||||
mut sframes := []string{}
|
||||
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
for i in 0 .. nr_actual_frames {
|
||||
sframes << unsafe { tos2(&byte(csymbols[i])) }
|
||||
}
|
||||
for sframe in sframes {
|
||||
executable := sframe.all_before('(')
|
||||
addr := sframe.all_after('[').all_before(']')
|
||||
beforeaddr := sframe.all_before('[')
|
||||
cmd := 'addr2line -e $executable $addr'
|
||||
// taken from os, to avoid depending on the os module inside builtin.v
|
||||
f := C.popen(&char(cmd.str), c'r')
|
||||
if isnil(f) {
|
||||
eprintln(sframe)
|
||||
continue
|
||||
}
|
||||
buf := [1000]byte{}
|
||||
mut output := ''
|
||||
unsafe {
|
||||
bp := &buf[0]
|
||||
for C.fgets(&char(bp), 1000, f) != 0 {
|
||||
output += tos(bp, vstrlen(bp))
|
||||
}
|
||||
}
|
||||
output = output.trim_space() + ':'
|
||||
if C.pclose(f) != 0 {
|
||||
eprintln(sframe)
|
||||
continue
|
||||
}
|
||||
if output in ['??:0:', '??:?:'] {
|
||||
output = ''
|
||||
}
|
||||
// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
|
||||
// NB: it is shortened here to just d. , just so that it fits, and so
|
||||
// that the common error file:lineno: line format is enforced.
|
||||
output = output.replace(' (discriminator', ': (d.')
|
||||
eprintln('${output:-55s} | ${addr:14s} | $beforeaddr')
|
||||
}
|
||||
output = output.trim_space() + ':'
|
||||
if C.pclose(f) != 0 {
|
||||
eprintln(sframe)
|
||||
continue
|
||||
}
|
||||
if output in ['??:0:', '??:?:'] {
|
||||
output = ''
|
||||
}
|
||||
// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
|
||||
// NB: it is shortened here to just d. , just so that it fits, and so
|
||||
// that the common error file:lineno: line format is enforced.
|
||||
output = output.replace(' (discriminator', ': (d.')
|
||||
eprintln('${output:-55s} | ${addr:14s} | $beforeaddr')
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -77,11 +77,18 @@ fn restore_codepage() {
|
||||
C.SetConsoleOutputCP(g_original_codepage)
|
||||
}
|
||||
|
||||
fn is_terminal(fd int) int {
|
||||
mut mode := u32(0)
|
||||
osfh := voidptr(C._get_osfhandle(fd))
|
||||
C.GetConsoleMode(osfh, voidptr(&mode))
|
||||
return int(mode)
|
||||
}
|
||||
|
||||
fn builtin_init() {
|
||||
g_original_codepage = C.GetConsoleOutputCP()
|
||||
C.SetConsoleOutputCP(C.CP_UTF8)
|
||||
C.atexit(restore_codepage)
|
||||
if is_atty(1) > 0 {
|
||||
if is_terminal(1) > 0 {
|
||||
C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
||||
C.SetConsoleMode(C.GetStdHandle(C.STD_ERROR_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
||||
unsafe {
|
||||
|
130
vlib/builtin/linux_bare/libc_impl.v
Normal file
130
vlib/builtin/linux_bare/libc_impl.v
Normal file
@ -0,0 +1,130 @@
|
||||
module builtin
|
||||
|
||||
[unsafe]
|
||||
pub fn memcpy(dest &byte, src &byte, n int) &byte {
|
||||
unsafe {
|
||||
for i in 0 .. n {
|
||||
dest[i] = src[i]
|
||||
}
|
||||
return dest
|
||||
}
|
||||
}
|
||||
|
||||
[export: 'malloc']
|
||||
[unsafe]
|
||||
fn __malloc(n int) &byte {
|
||||
return unsafe { malloc(n) }
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn strlen(s &byte) int {
|
||||
mut i := 0
|
||||
for ; unsafe { s[i] } != 0; i++ {}
|
||||
return i
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn realloc(old_area &byte, new_size int) &byte {
|
||||
if old_area == 0 {
|
||||
return unsafe { malloc(new_size) }
|
||||
}
|
||||
if new_size == 0 {
|
||||
unsafe { free(old_area) }
|
||||
return 0
|
||||
}
|
||||
old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
|
||||
if new_size <= old_size {
|
||||
return old_area
|
||||
} else {
|
||||
new_area := unsafe { malloc(new_size) }
|
||||
unsafe { memmove(new_area, old_area, int(old_size)) }
|
||||
unsafe { free(old_area) }
|
||||
return new_area
|
||||
}
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn memset(_s &byte, _c int, n int) &byte {
|
||||
c := char(_c)
|
||||
mut s := unsafe { &char(_s) }
|
||||
for i in 0 .. int(n) {
|
||||
unsafe {
|
||||
s[i] = c
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
fn memmove(dest &byte, src &byte, n int) &byte {
|
||||
mut temp_buf := unsafe { malloc(n) }
|
||||
for i in 0 .. int(n) {
|
||||
unsafe {
|
||||
temp_buf[i] = src[i]
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 .. int(n) {
|
||||
unsafe {
|
||||
dest[i] = temp_buf[i]
|
||||
}
|
||||
}
|
||||
unsafe { free(temp_buf) }
|
||||
return dest
|
||||
}
|
||||
|
||||
[export: 'calloc']
|
||||
[unsafe]
|
||||
fn __calloc(nmemb int, size int) &byte {
|
||||
new_area := unsafe { malloc(nmemb * size) }
|
||||
unsafe { memset(new_area, 0, nmemb * size) }
|
||||
return new_area
|
||||
}
|
||||
|
||||
fn getchar() int {
|
||||
x := byte(0)
|
||||
sys_read(C.stdin, &x, 1)
|
||||
return int(x)
|
||||
}
|
||||
|
||||
fn memcmp(a &byte, b &byte, n int) int {
|
||||
for i in 0 .. int(n) {
|
||||
if unsafe { a[i] != b[i] } {
|
||||
unsafe {
|
||||
return a[i] - b[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
[export: 'free']
|
||||
[unsafe]
|
||||
fn __free(ptr &byte) {
|
||||
err := mm_free(ptr)
|
||||
if err != .enoerror {
|
||||
eprintln('free error:')
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn vsprintf(str &char, format &char, ap &byte) int {
|
||||
panic('vsprintf(): string interpolation is not supported in `-freestanding`')
|
||||
}
|
||||
|
||||
fn vsnprintf(str &char, size int, format &char, ap &byte) int {
|
||||
panic('vsnprintf(): string interpolation is not supported in `-freestanding`')
|
||||
}
|
||||
|
||||
// not really needed
|
||||
fn bare_read(buf &byte, count u64) (i64, Errno) {
|
||||
return sys_read(0, buf, count)
|
||||
}
|
||||
|
||||
fn bare_print(buf &byte, len u64) {
|
||||
sys_write(1, buf, len)
|
||||
}
|
||||
|
||||
fn bare_eprint(buf &byte, len u64) {
|
||||
sys_write(2, buf, len)
|
||||
}
|
431
vlib/builtin/linux_bare/linux_syscalls.v
Normal file
431
vlib/builtin/linux_bare/linux_syscalls.v
Normal file
@ -0,0 +1,431 @@
|
||||
module builtin
|
||||
|
||||
enum SigIndex {
|
||||
si_signo = 0x00
|
||||
si_code = 0x02
|
||||
si_pid = 0x04
|
||||
si_uid = 0x05
|
||||
si_status = 0x06
|
||||
si_size = 0x80
|
||||
}
|
||||
|
||||
enum Signo {
|
||||
sighup = 1 // Hangup.
|
||||
sigint = 2 // Interactive attention signal.
|
||||
sigquit = 3 // Quit.
|
||||
sigill = 4 // Illegal instruction.
|
||||
sigtrap = 5 // Trace/breakpoint trap.
|
||||
sigabrt = 6 // Abnormal termination.
|
||||
sigbus = 7
|
||||
sigfpe = 8 // Erroneous arithmetic operation.
|
||||
sigkill = 9 // Killed.
|
||||
sigusr1 = 10
|
||||
sigsegv = 11 // Invalid access to memory.
|
||||
sigusr2 = 12
|
||||
sigpipe = 13 // Broken pipe.
|
||||
sigalrm = 14 // Alarm clock.
|
||||
sigterm = 15 // Termination request.
|
||||
sigstkflt = 16
|
||||
sigchld = 17
|
||||
sigcont = 18
|
||||
sigstop = 19
|
||||
sigtstp = 20
|
||||
sigttin = 21 // Background read from control terminal.
|
||||
sigttou = 22 // Background write to control terminal.
|
||||
sigurg = 23
|
||||
sigxcpu = 24 // CPU time limit exceeded.
|
||||
sigxfsz = 25 // File size limit exceeded.
|
||||
sigvtalrm = 26 // Virtual timer expired.
|
||||
sigprof = 27 // Profiling timer expired.
|
||||
sigwinch = 28
|
||||
sigpoll = 29
|
||||
sigsys = 31
|
||||
}
|
||||
|
||||
// List of all the errors returned by syscalls
|
||||
enum Errno {
|
||||
enoerror = 0x00000000
|
||||
eperm = 0x00000001
|
||||
enoent = 0x00000002
|
||||
esrch = 0x00000003
|
||||
eintr = 0x00000004
|
||||
eio = 0x00000005
|
||||
enxio = 0x00000006
|
||||
e2big = 0x00000007
|
||||
enoexec = 0x00000008
|
||||
ebadf = 0x00000009
|
||||
echild = 0x0000000a
|
||||
eagain = 0x0000000b
|
||||
enomem = 0x0000000c
|
||||
eacces = 0x0000000d
|
||||
efault = 0x0000000e
|
||||
enotblk = 0x0000000f
|
||||
ebusy = 0x00000010
|
||||
eexist = 0x00000011
|
||||
exdev = 0x00000012
|
||||
enodev = 0x00000013
|
||||
enotdir = 0x00000014
|
||||
eisdir = 0x00000015
|
||||
einval = 0x00000016
|
||||
enfile = 0x00000017
|
||||
emfile = 0x00000018
|
||||
enotty = 0x00000019
|
||||
etxtbsy = 0x0000001a
|
||||
efbig = 0x0000001b
|
||||
enospc = 0x0000001c
|
||||
espipe = 0x0000001d
|
||||
erofs = 0x0000001e
|
||||
emlink = 0x0000001f
|
||||
epipe = 0x00000020
|
||||
edom = 0x00000021
|
||||
erange = 0x00000022
|
||||
}
|
||||
|
||||
enum MemProt {
|
||||
prot_read = 0x1
|
||||
prot_write = 0x2
|
||||
prot_exec = 0x4
|
||||
prot_none = 0x0
|
||||
prot_growsdown = 0x01000000
|
||||
prot_growsup = 0x02000000
|
||||
}
|
||||
|
||||
enum MapFlags {
|
||||
map_shared = 0x01
|
||||
map_private = 0x02
|
||||
map_shared_validate = 0x03
|
||||
map_type = 0x0f
|
||||
map_fixed = 0x10
|
||||
map_file = 0x00
|
||||
map_anonymous = 0x20
|
||||
map_huge_shift = 26
|
||||
map_huge_mask = 0x3f
|
||||
}
|
||||
|
||||
// const (
|
||||
// fcntlf_dupfd = 0x00000000
|
||||
// fcntlf_exlck = 0x00000004
|
||||
// fcntlf_getfd = 0x00000001
|
||||
// fcntlf_getfl = 0x00000003
|
||||
// fcntlf_getlk = 0x00000005
|
||||
// fcntlf_getlk64 = 0x0000000c
|
||||
// fcntlf_getown = 0x00000009
|
||||
// fcntlf_getowner_uids = 0x00000011
|
||||
// fcntlf_getown_ex = 0x00000010
|
||||
// fcntlf_getsig = 0x0000000b
|
||||
// fcntlf_ofd_getlk = 0x00000024
|
||||
// fcntlf_ofd_setlk = 0x00000025
|
||||
// fcntlf_ofd_setlkw = 0x00000026
|
||||
// fcntlf_owner_pgrp = 0x00000002
|
||||
// fcntlf_owner_pid = 0x00000001
|
||||
// fcntlf_owner_tid = 0x00000000
|
||||
// fcntlf_rdlck = 0x00000000
|
||||
// fcntlf_setfd = 0x00000002
|
||||
// fcntlf_setfl = 0x00000004
|
||||
// fcntlf_setlk = 0x00000006
|
||||
// fcntlf_setlk64 = 0x0000000d
|
||||
// fcntlf_setlkw = 0x00000007
|
||||
// fcntlf_setlkw64 = 0x0000000e
|
||||
// fcntlf_setown = 0x00000008
|
||||
// fcntlf_setown_ex = 0x0000000f
|
||||
// fcntlf_setsig = 0x0000000a
|
||||
// fcntlf_shlck = 0x00000008
|
||||
// fcntlf_unlck = 0x00000002
|
||||
// fcntlf_wrlck = 0x00000001
|
||||
// fcntllock_ex = 0x00000002
|
||||
// fcntllock_mand = 0x00000020
|
||||
// fcntllock_nb = 0x00000004
|
||||
// fcntllock_read = 0x00000040
|
||||
// fcntllock_rw = 0x000000c0
|
||||
// fcntllock_sh = 0x00000001
|
||||
// fcntllock_un = 0x00000008
|
||||
// fcntllock_write = 0x00000080
|
||||
// fcntlo_accmode = 0x00000003
|
||||
// fcntlo_append = 0x00000400
|
||||
// fcntlo_cloexec = 0x00080000
|
||||
// fcntlo_creat = 0x00000040
|
||||
// fcntlo_direct = 0x00004000
|
||||
// fcntlo_directory = 0x00010000
|
||||
// fcntlo_dsync = 0x00001000
|
||||
// fcntlo_excl = 0x00000080
|
||||
// fcntlo_largefile = 0x00008000
|
||||
// fcntlo_ndelay = 0x00000800
|
||||
// fcntlo_noatime = 0x00040000
|
||||
// fcntlo_noctty = 0x00000100
|
||||
// fcntlo_nofollow = 0x00020000
|
||||
// fcntlo_nonblock = 0x00000800
|
||||
// fcntlo_path = 0x00200000
|
||||
// fcntlo_rdonly = 0x00000000
|
||||
// fcntlo_rdwr = 0x00000002
|
||||
// fcntlo_trunc = 0x00000200
|
||||
// fcntlo_wronly = 0x00000001
|
||||
// )
|
||||
|
||||
/*
|
||||
Paraphrased from "man 2 waitid" on Linux
|
||||
|
||||
Upon successful return, waitid() fills in the
|
||||
following fields of the siginfo_t structure
|
||||
pointed to by infop:
|
||||
|
||||
si_pid, offset 0x10, int index 0x04:
|
||||
The process ID of the child.
|
||||
|
||||
si_uid: offset 0x14, int index 0x05
|
||||
The real user ID of the child.
|
||||
|
||||
si_signo: offset 0x00, int index 0x00
|
||||
Always set to SIGCHLD.
|
||||
|
||||
si_status: ofset 0x18, int index 0x06
|
||||
1 the exit status of the child, as given to _exit(2)
|
||||
(or exit(3)) (sc_sys.cld_exited)
|
||||
2 the signal that caused the child to terminate, stop,
|
||||
or continue.
|
||||
3 The si_code field can be used to determine how to
|
||||
interpret this field.
|
||||
|
||||
si_code, set to one of (enum Wi_si_code), offset 0x08, int index 0x02:
|
||||
CLD_EXITED (child called _exit(2));
|
||||
CLD_KILLED (child killed by signal);
|
||||
CLD_DUMPED (child killed by signal, and dumped core);
|
||||
CLD_STOPPED (child stopped by signal);
|
||||
CLD_TRAPPED (traced child has trapped);
|
||||
CLD_CONTINUED (child continued by SIGCONT).
|
||||
*/
|
||||
|
||||
const (
|
||||
wp_sys_wnohang = u64(0x00000001)
|
||||
wp_sys_wuntraced = u64(0x00000002)
|
||||
wp_sys_wstopped = u64(0x00000002)
|
||||
wp_sys_wexited = u64(0x00000004)
|
||||
wp_sys_wcontinued = u64(0x00000008)
|
||||
wp_sys_wnowait = u64(0x01000000) // don't reap, just poll status.
|
||||
wp_sys___wnothread = u64(0x20000000) // don't wait on children of other threads in this group
|
||||
wp_sys___wall = u64(0x40000000) // wait on all children, regardless of type
|
||||
wp_sys___wclone = u64(0x80000000) // wait only on non-sigchld children
|
||||
)
|
||||
|
||||
// First argument to waitid:
|
||||
enum WiWhich {
|
||||
p_all = 0
|
||||
p_pid = 1
|
||||
p_pgid = 2
|
||||
}
|
||||
|
||||
enum WiSiCode {
|
||||
cld_exited = 1 // child has exited
|
||||
cld_killed = 2 // child was killed
|
||||
cld_dumped = 3 // child terminated abnormally
|
||||
cld_trapped = 4 // traced child has trapped
|
||||
cld_stopped = 5 // child has stopped
|
||||
cld_continued = 6 // stopped child has continued
|
||||
}
|
||||
|
||||
fn split_int_errno(rc_in u64) (i64, Errno) {
|
||||
rc := i64(rc_in)
|
||||
if rc < 0 {
|
||||
return i64(-1), Errno(-rc)
|
||||
}
|
||||
return rc, Errno.enoerror
|
||||
}
|
||||
|
||||
// 0 sys_read
|
||||
fn sys_read(fd i64, buf &byte, count u64) (i64, Errno) {
|
||||
return split_int_errno(sys_call3(0, u64(fd), u64(buf), count))
|
||||
}
|
||||
|
||||
// 1 sys_write
|
||||
fn sys_write(fd i64, buf &byte, count u64) (i64, Errno) {
|
||||
return split_int_errno(sys_call3(1, u64(fd), u64(buf), count))
|
||||
}
|
||||
|
||||
// 2 sys_open
|
||||
fn sys_open(filename &byte, flags i64, mode int) (i64, Errno) {
|
||||
return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode)))
|
||||
}
|
||||
|
||||
// 3 sys_close
|
||||
fn sys_close(fd i64) Errno {
|
||||
return Errno(-i64(sys_call1(3, u64(fd))))
|
||||
}
|
||||
|
||||
// 9 sys_mmap
|
||||
fn sys_mmap(addr &byte, len u64, prot MemProt, flags MapFlags, fildes u64, off u64) (&byte, Errno) {
|
||||
rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off)
|
||||
a, e := split_int_errno(rc)
|
||||
return &byte(a), e
|
||||
}
|
||||
|
||||
// 11 sys_munmap
|
||||
fn sys_munmap(addr voidptr, len u64) Errno {
|
||||
return Errno(-sys_call2(11, u64(addr), len))
|
||||
}
|
||||
|
||||
// 22 sys_pipe
|
||||
fn sys_pipe(filedes &int) Errno {
|
||||
return Errno(sys_call1(22, u64(filedes)))
|
||||
}
|
||||
|
||||
// 24 sys_sched_yield
|
||||
fn sys_sched_yield() Errno {
|
||||
return Errno(sys_call0(24))
|
||||
}
|
||||
|
||||
// 28 sys_madvise
|
||||
fn sys_madvise(addr voidptr, len u64, advice int) Errno {
|
||||
return Errno(sys_call3(28, u64(addr), len, u64(advice)))
|
||||
}
|
||||
|
||||
// 39 sys_getpid
|
||||
fn sys_getpid() int {
|
||||
return int(sys_call0(39))
|
||||
}
|
||||
|
||||
// 57 sys_fork
|
||||
fn sys_fork() int {
|
||||
return int(sys_call0(57))
|
||||
}
|
||||
|
||||
// 58 sys_vfork
|
||||
fn sys_vfork() int {
|
||||
return int(sys_call0(58))
|
||||
}
|
||||
|
||||
// 33 sys_dup2
|
||||
fn sys_dup2(oldfd int, newfd int) (i64, Errno) {
|
||||
return split_int_errno(sys_call2(33, u64(oldfd), u64(newfd)))
|
||||
}
|
||||
|
||||
// 59 sys_execve
|
||||
fn sys_execve(filename &byte, argv []&byte, envp []&byte) int {
|
||||
return int(sys_call3(59, u64(filename), argv.data, envp.data))
|
||||
}
|
||||
|
||||
// 60 sys_exit
|
||||
fn sys_exit(ec int) {
|
||||
sys_call1(60, u64(ec))
|
||||
}
|
||||
|
||||
// 102 sys_getuid
|
||||
fn sys_getuid() int {
|
||||
return int(sys_call0(102))
|
||||
}
|
||||
|
||||
// 247 sys_waitid
|
||||
fn sys_waitid(which WiWhich, pid int, infop &int, options int, ru voidptr) Errno {
|
||||
return Errno(sys_call5(247, u64(which), u64(pid), u64(infop), u64(options), u64(ru)))
|
||||
}
|
||||
|
||||
fn sys_call0(scn u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call1(scn u64, arg1 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call2(scn u64, arg1 u64, arg2 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
S (arg2)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call3(scn u64, arg1 u64, arg2 u64, arg3 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
S (arg2)
|
||||
d (arg3)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call4(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
mov r10, arg4
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
S (arg2)
|
||||
d (arg3)
|
||||
r (arg4)
|
||||
; r10
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call5(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
mov r10, arg4
|
||||
mov r8, arg5
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
S (arg2)
|
||||
d (arg3)
|
||||
r (arg4)
|
||||
r (arg5)
|
||||
; r10
|
||||
r8
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn sys_call6(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64, arg6 u64) u64 {
|
||||
mut res := u64(0)
|
||||
asm amd64 {
|
||||
mov r10, arg4
|
||||
mov r8, arg5
|
||||
mov r9, arg6
|
||||
syscall
|
||||
; =a (res)
|
||||
; a (scn)
|
||||
D (arg1)
|
||||
S (arg2)
|
||||
d (arg3)
|
||||
r (arg4)
|
||||
r (arg5)
|
||||
r (arg6)
|
||||
; r10
|
||||
r8
|
||||
r9
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
asm amd64 {
|
||||
.globl _start
|
||||
_start:
|
||||
call main
|
||||
mov rax, 60
|
||||
xor rdi, rdi
|
||||
syscall
|
||||
ret
|
||||
}
|
29
vlib/builtin/linux_bare/memory_managment.v
Normal file
29
vlib/builtin/linux_bare/memory_managment.v
Normal file
@ -0,0 +1,29 @@
|
||||
module builtin
|
||||
|
||||
fn mm_alloc(size u64) (&byte, Errno) {
|
||||
// BEGIN CONSTS
|
||||
// the constants need to be here, since the initialization of other constants,
|
||||
// which happen before these ones would, require malloc
|
||||
mem_prot := MemProt(int(MemProt.prot_read) | int(MemProt.prot_write))
|
||||
map_flags := MapFlags(int(MapFlags.map_private) | int(MapFlags.map_anonymous))
|
||||
// END CONSTS
|
||||
|
||||
a, e := sys_mmap(&byte(0), size + sizeof(u64), mem_prot, map_flags, -1, 0)
|
||||
if e == .enoerror {
|
||||
unsafe {
|
||||
mut ap := &u64(a)
|
||||
*ap = size
|
||||
x2 := &byte(a + sizeof(u64))
|
||||
return x2, e
|
||||
}
|
||||
}
|
||||
return &byte(0), e
|
||||
}
|
||||
|
||||
fn mm_free(addr &byte) Errno {
|
||||
unsafe {
|
||||
ap := &u64(addr - sizeof(u64))
|
||||
size := *ap
|
||||
return sys_munmap(addr - sizeof(u64), size + sizeof(u64))
|
||||
}
|
||||
}
|
@ -997,7 +997,11 @@ pub fn (s string) to_lower() string {
|
||||
unsafe {
|
||||
mut b := malloc(s.len + 1)
|
||||
for i in 0 .. s.len {
|
||||
b[i] = byte(C.tolower(s.str[i]))
|
||||
if s.str[i] >= `A` && s.str[i] <= `Z` {
|
||||
b[i] = s.str[i] + 32
|
||||
} else {
|
||||
b[i] = s.str[i]
|
||||
}
|
||||
}
|
||||
b[s.len] = 0
|
||||
return tos(b, s.len)
|
||||
@ -1021,7 +1025,11 @@ pub fn (s string) to_upper() string {
|
||||
unsafe {
|
||||
mut b := malloc(s.len + 1)
|
||||
for i in 0 .. s.len {
|
||||
b[i] = byte(C.toupper(s.str[i]))
|
||||
if s.str[i] >= `a` && s.str[i] <= `z` {
|
||||
b[i] = s.str[i] - 32
|
||||
} else {
|
||||
b[i] = s.str[i]
|
||||
}
|
||||
}
|
||||
b[s.len] = 0
|
||||
return tos(b, s.len)
|
||||
@ -1539,7 +1547,11 @@ pub fn (s &string) free() {
|
||||
return
|
||||
}
|
||||
if s.is_lit == -98761234 {
|
||||
C.printf(c'double string.free() detected\n')
|
||||
$if freestanding {
|
||||
bare_eprint(c'double string.free() detected\n', u64(unsafe { C.strlen(c'double string.free() detected\n') }))
|
||||
} $else {
|
||||
C.printf(c'double string.free() detected\n')
|
||||
}
|
||||
return
|
||||
}
|
||||
if s.is_lit == 1 || s.len == 0 {
|
||||
|
12
vlib/os/os.v
12
vlib/os/os.v
@ -629,3 +629,15 @@ pub fn execute_or_panic(cmd string) Result {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
||||
pub fn is_atty(fd int) int {
|
||||
$if windows {
|
||||
mut mode := u32(0)
|
||||
osfh := voidptr(C._get_osfhandle(fd))
|
||||
C.GetConsoleMode(osfh, voidptr(&mode))
|
||||
return int(mode)
|
||||
} $else {
|
||||
return C.isatty(fd)
|
||||
}
|
||||
}
|
||||
|
@ -125,8 +125,8 @@ fn supports_escape_sequences(fd int) bool {
|
||||
return true
|
||||
}
|
||||
// 4 is enable_virtual_terminal_processing
|
||||
return (is_atty(fd) & 0x0004) > 0
|
||||
return (os.is_atty(fd) & 0x0004) > 0
|
||||
} $else {
|
||||
return is_atty(fd) > 0
|
||||
return os.is_atty(fd) > 0
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int
|
||||
|
||||
// get_terminal_size returns a number of colums and rows of terminal window.
|
||||
pub fn get_terminal_size() (int, int) {
|
||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
return default_columns_size, default_rows_size
|
||||
}
|
||||
w := C.winsize{}
|
||||
@ -27,7 +27,7 @@ pub fn get_terminal_size() (int, int) {
|
||||
|
||||
// get_cursor_position returns a Coord containing the current cursor position
|
||||
pub fn get_cursor_position() Coord {
|
||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
return Coord{
|
||||
x: 0
|
||||
y: 0
|
||||
@ -89,7 +89,7 @@ pub fn get_cursor_position() Coord {
|
||||
|
||||
// set_terminal_title change the terminal title
|
||||
pub fn set_terminal_title(title string) bool {
|
||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||
return true
|
||||
}
|
||||
print('\033]0')
|
||||
|
@ -57,7 +57,7 @@ fn C.ScrollConsoleScreenBuffer(output C.HANDLE, scroll_rect &C.SMALL_RECT, clip_
|
||||
|
||||
// get_terminal_size returns a number of colums and rows of terminal window.
|
||||
pub fn get_terminal_size() (int, int) {
|
||||
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||
if os.is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
||||
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
||||
columns := int(info.srWindow.Right - info.srWindow.Left + 1)
|
||||
@ -71,7 +71,7 @@ pub fn get_terminal_size() (int, int) {
|
||||
// get_cursor_position returns a Coord containing the current cursor position
|
||||
pub fn get_cursor_position() Coord {
|
||||
mut res := Coord{}
|
||||
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||
if os.is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
||||
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
||||
res.x = info.dwCursorPosition.X
|
||||
|
@ -60,7 +60,7 @@ fn (mut ctx Context) termios_setup() ? {
|
||||
// store the current title, so restore_terminal_state can get it back
|
||||
save_title()
|
||||
|
||||
if !ctx.cfg.skip_init_checks && !(is_atty(C.STDIN_FILENO) != 0 && is_atty(C.STDOUT_FILENO) != 0) {
|
||||
if !ctx.cfg.skip_init_checks && !(os.is_atty(C.STDIN_FILENO) != 0 && os.is_atty(C.STDOUT_FILENO) != 0) {
|
||||
return error('not running under a TTY')
|
||||
}
|
||||
|
||||
|
@ -3804,7 +3804,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
|
||||
stmt.pos)
|
||||
}
|
||||
if c.pref.backend == .js {
|
||||
c.error('inline assembly is not supported in js backend', stmt.pos)
|
||||
c.error('inline assembly is not supported in the js backend', stmt.pos)
|
||||
}
|
||||
if c.pref.backend == .c && c.pref.ccompiler_type == .msvc {
|
||||
c.error('msvc compiler does not support inline assembly', stmt.pos)
|
||||
@ -3857,16 +3857,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
|
||||
|
||||
fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
|
||||
match mut arg {
|
||||
ast.AsmAlias {
|
||||
name := arg.name
|
||||
if name !in aliases && name !in stmt.local_labels && name !in c.file.global_labels {
|
||||
mut possible := aliases.clone()
|
||||
possible << stmt.local_labels
|
||||
possible << c.file.global_labels
|
||||
suggestion := util.new_suggestion(name, possible)
|
||||
c.error(suggestion.say('alias or label `$arg.name` does not exist'), arg.pos)
|
||||
}
|
||||
}
|
||||
ast.AsmAlias {}
|
||||
ast.AsmAddressing {
|
||||
if arg.scale !in [-1, 1, 2, 4, 8] {
|
||||
c.error('scale must be one of 1, 2, 4, or 8', arg.pos)
|
||||
@ -5368,7 +5359,19 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||
} else if !is_comptime_type_is_expr {
|
||||
found_branch = true // If a branch wasn't skipped, the rest must be
|
||||
}
|
||||
if !c.skip_flags || c.pref.output_cross_c {
|
||||
if !c.skip_flags {
|
||||
c.stmts(branch.stmts)
|
||||
} else if c.pref.output_cross_c {
|
||||
mut is_freestanding_block := false
|
||||
if branch.cond is ast.Ident {
|
||||
if branch.cond.name == 'freestanding' {
|
||||
is_freestanding_block = true
|
||||
}
|
||||
}
|
||||
if is_freestanding_block {
|
||||
branch.stmts = []
|
||||
node.branches[i].stmts = []
|
||||
}
|
||||
c.stmts(branch.stmts)
|
||||
} else if !is_comptime_type_is_expr {
|
||||
node.branches[i].stmts = []
|
||||
@ -5603,7 +5606,7 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
|
||||
'glibc' { return false } // TODO
|
||||
'prealloc' { return !c.pref.prealloc }
|
||||
'no_bounds_checking' { return cond.name !in c.pref.compile_defines_all }
|
||||
'freestanding' { return !c.pref.is_bare }
|
||||
'freestanding' { return !c.pref.is_bare || c.pref.output_cross_c }
|
||||
else { return false }
|
||||
}
|
||||
} else if cond.name !in c.pref.compile_defines_all {
|
||||
|
@ -1,5 +0,0 @@
|
||||
vlib/v/checker/tests/asm_alias_does_not_exist.vv:2:11: error: alias or label `a` does not exist
|
||||
1 | asm amd64 {
|
||||
2 | mov ebx, a
|
||||
| ^
|
||||
3 | }
|
@ -1,3 +0,0 @@
|
||||
asm amd64 {
|
||||
mov ebx, a
|
||||
}
|
@ -392,7 +392,6 @@ pub fn (mut g Gen) init() {
|
||||
} else {
|
||||
g.cheaders.writeln(c_headers)
|
||||
}
|
||||
g.definitions.writeln('void _STR_PRINT_ARG(const char*, char**, int*, int*, int, ...);')
|
||||
g.definitions.writeln('string _STR(const char*, int, ...);')
|
||||
g.definitions.writeln('string _STR_TMP(const char*, ...);')
|
||||
}
|
||||
@ -1893,7 +1892,7 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
|
||||
ast.AsmAlias {
|
||||
name := arg.name
|
||||
if name in stmt.local_labels || name in stmt.global_labels
|
||||
|| name in g.file.global_labels {
|
||||
|| name in g.file.global_labels || stmt.is_top_level {
|
||||
asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name }
|
||||
g.write(asm_formatted_name)
|
||||
} else {
|
||||
@ -5466,7 +5465,9 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
||||
g.type_definitions.writeln('} $name;')
|
||||
}
|
||||
} else {
|
||||
g.type_definitions.writeln('typedef pthread_t $name;')
|
||||
if !g.pref.is_bare {
|
||||
g.type_definitions.writeln('typedef pthread_t $name;')
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.SumType {
|
||||
|
@ -5,18 +5,18 @@ module c
|
||||
// for each constant, during C code generation.
|
||||
const (
|
||||
// V_COMMIT_HASH is generated by cmd/tools/gen_vc.v .
|
||||
c_commit_hash_default = '
|
||||
c_commit_hash_default = '
|
||||
#ifndef V_COMMIT_HASH
|
||||
#define V_COMMIT_HASH "@@@"
|
||||
#endif
|
||||
'
|
||||
// V_CURRENT_COMMIT_HASH is updated, when V is rebuilt inside a git repo.
|
||||
c_current_commit_hash_default = '
|
||||
c_current_commit_hash_default = '
|
||||
#ifndef V_CURRENT_COMMIT_HASH
|
||||
#define V_CURRENT_COMMIT_HASH "@@@"
|
||||
#endif
|
||||
'
|
||||
c_concurrency_helpers = '
|
||||
c_concurrency_helpers = '
|
||||
typedef struct __shared_map __shared_map;
|
||||
struct __shared_map { map val; sync__RwMutex mtx; };
|
||||
static inline voidptr __dup_shared_map(voidptr src, int sz) {
|
||||
@ -47,7 +47,136 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l)
|
||||
}
|
||||
}
|
||||
'
|
||||
c_common_macros = '
|
||||
c_str_fn_defs = '
|
||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||
va_list args;
|
||||
va_start(args, guess);
|
||||
// NB: (*memsize - *nbytes) === how much free space is left at the end of the current buffer refbufp
|
||||
// *memsize === total length of the buffer refbufp
|
||||
// *nbytes === already occupied bytes of buffer refbufp
|
||||
// guess === how many bytes were taken during the current vsnprintf run
|
||||
for(;;) {
|
||||
int remaining_space = *memsize - *nbytes;
|
||||
if (guess < remaining_space) {
|
||||
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
||||
if (guess < remaining_space) { // result did fit into buffer
|
||||
*nbytes += guess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// increase buffer (somewhat exponentially)
|
||||
*memsize += guess + 3 * (*memsize) / 2;
|
||||
#ifdef _VGCBOEHM
|
||||
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||
#else
|
||||
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
||||
#endif
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
string _STR(const char *fmt, int nfmts, ...) {
|
||||
va_list argptr;
|
||||
int memsize = 128;
|
||||
int nbytes = 0;
|
||||
#ifdef _VGCBOEHM
|
||||
char* buf = (char*)GC_MALLOC(memsize);
|
||||
#else
|
||||
char* buf = (char*)malloc(memsize);
|
||||
#endif
|
||||
va_start(argptr, nfmts);
|
||||
for (int i=0; i<nfmts; ++i) {
|
||||
int k = strlen(fmt);
|
||||
bool is_fspec = false;
|
||||
for (int j=0; j<k; ++j) {
|
||||
if (fmt[j] == \'%\') {
|
||||
j++;
|
||||
if (fmt[j] != \'%\') {
|
||||
is_fspec = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_fspec) {
|
||||
char f = fmt[k-1];
|
||||
char fup = f & 0xdf; // toupper
|
||||
bool l = fmt[k-2] == \'l\';
|
||||
bool ll = l && fmt[k-3] == \'l\';
|
||||
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
||||
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
||||
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
||||
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
||||
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
||||
} else if (f == \'p\') {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
||||
} else if (f == \'C\') { // a C string
|
||||
char* sptr = va_arg(argptr, char*);
|
||||
char* fmt_no_c = (char*)v_malloc(k+4);
|
||||
memcpy(fmt_no_c, fmt, k);
|
||||
fmt_no_c[k-2]=\'C\';
|
||||
fmt_no_c[k-1]=\'"\';
|
||||
fmt_no_c[k]=\'%\';
|
||||
fmt_no_c[k+1]=\'s\';
|
||||
fmt_no_c[k+2]=\'"\';
|
||||
fmt_no_c[k+3]=0;
|
||||
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
||||
v_free(fmt_no_c);
|
||||
} else if (f == \'s\') { // v string
|
||||
string s = va_arg(argptr, string);
|
||||
if (fmt[k-4] == \'*\') { // %*.*s
|
||||
int fwidth = va_arg(argptr, int);
|
||||
if (fwidth < 0)
|
||||
fwidth -= (s.len - utf8_str_visible_length(s));
|
||||
else
|
||||
fwidth += (s.len - utf8_str_visible_length(s));
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, fwidth, s.len, s.str);
|
||||
} else { // %.*s
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
||||
}
|
||||
} else {
|
||||
//v_panic(tos3(\'Invaid format specifier\'));
|
||||
}
|
||||
} else {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
||||
}
|
||||
fmt += k+1;
|
||||
}
|
||||
va_end(argptr);
|
||||
buf[nbytes] = 0;
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts(\'_STR:\');
|
||||
puts(buf);
|
||||
#endif
|
||||
|
||||
#if _VAUTOFREE
|
||||
//g_cur_str = (byteptr)buf;
|
||||
#endif
|
||||
return tos2((byteptr)buf);
|
||||
}
|
||||
|
||||
string _STR_TMP(const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
size_t len = vsnprintf(0, 0, fmt, argptr) + 1;
|
||||
va_end(argptr);
|
||||
va_start(argptr, fmt);
|
||||
vsprintf((char *)g_str_buf, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts(\'_STR_TMP:\');
|
||||
//puts(g_str_buf);
|
||||
#endif
|
||||
string res = tos(g_str_buf, len);
|
||||
res.is_lit = 1;
|
||||
return res;
|
||||
|
||||
} // endof _STR_TMP
|
||||
|
||||
'
|
||||
c_common_macros = '
|
||||
#define EMPTY_VARG_INITIALIZATION 0
|
||||
#define EMPTY_STRUCT_DECLARATION
|
||||
#define EMPTY_STRUCT_INITIALIZATION 0
|
||||
@ -126,12 +255,6 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l)
|
||||
#define V64_PRINTFORMAT "0x%llx"
|
||||
#endif
|
||||
#endif
|
||||
'
|
||||
c_headers = '
|
||||
// c_headers
|
||||
typedef int (*qsort_callback_func)(const void*, const void*);
|
||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define VV_EXPORTED_SYMBOL extern __declspec(dllexport)
|
||||
@ -167,144 +290,8 @@ typedef int (*qsort_callback_func)(const void*, const void*);
|
||||
#undef __has_include
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#if defined __has_include
|
||||
#if __has_include (<execinfo.h>)
|
||||
#include <execinfo.h>
|
||||
#else
|
||||
// Most probably musl OR __ANDROID__ ...
|
||||
int backtrace (void **__array, int __size) { return 0; }
|
||||
char **backtrace_symbols (void *const *__array, int __size){ return 0; }
|
||||
void backtrace_symbols_fd (void *const *__array, int __size, int __fd){}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#include "fns.h"
|
||||
#include <signal.h>
|
||||
#include <stdarg.h> // for va_list
|
||||
#include <string.h> // memcpy
|
||||
|
||||
#if INTPTR_MAX == INT32_MAX
|
||||
#define TARGET_IS_32BIT 1
|
||||
#elif INTPTR_MAX == INT64_MAX
|
||||
#define TARGET_IS_64BIT 1
|
||||
#else
|
||||
#error "The environment is not 32 or 64-bit."
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
|
||||
#define TARGET_ORDER_IS_BIG
|
||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86)
|
||||
#define TARGET_ORDER_IS_LITTLE
|
||||
#else
|
||||
#error "Unknown architecture endianness"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <ctype.h>
|
||||
#include <locale.h> // tolower
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h> // sleep
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) && !defined(_WIN32)
|
||||
#error Cygwin is not supported, please use MinGW or Visual Studio.
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
$c_common_macros
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WINVER 0x0600
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#ifndef WIN32_FULL
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#include <io.h> // _waccess
|
||||
#include <direct.h> // _wgetcwd
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||
#define _Atomic volatile
|
||||
|
||||
// MSVC cannot parse some things properly
|
||||
#undef EMPTY_STRUCT_DECLARATION
|
||||
#undef OPTION_CAST
|
||||
|
||||
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable
|
||||
#define OPTION_CAST(x)
|
||||
#undef __NOINLINE
|
||||
#undef __IRQHANDLER
|
||||
#define __NOINLINE __declspec(noinline)
|
||||
#define __IRQHANDLER __declspec(naked)
|
||||
|
||||
#include <dbghelp.h>
|
||||
#pragma comment(lib, "Dbghelp")
|
||||
#endif
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#ifndef PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
|
||||
// musl does not have that
|
||||
#define pthread_rwlockattr_setkind_np(a, b)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// g_live_info is used by live.info()
|
||||
static void* g_live_info = NULL;
|
||||
|
||||
//============================== HELPER C MACROS =============================*/
|
||||
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
||||
// `"" s` is used to enforce a string literal argument
|
||||
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||
// take the address of an rvalue
|
||||
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
||||
// copy something to the heap
|
||||
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
||||
#define _IN_MAP(val, m) map_exists(m, val)
|
||||
|
||||
'
|
||||
c_unsigned_comparison_functions = '
|
||||
// unsigned/signed comparisons
|
||||
static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; }
|
||||
static inline bool _us32_ge(uint32_t a, int32_t b) { return a >= INT32_MAX || (int32_t)a >= b; }
|
||||
@ -318,32 +305,8 @@ static inline bool _us64_eq(uint64_t a, int64_t b) { return a <= INT64_MAX && (i
|
||||
static inline bool _us64_ne(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a != b; }
|
||||
static inline bool _us64_le(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a <= b; }
|
||||
static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (int64_t)a < b; }
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__))
|
||||
#undef PRId64
|
||||
#undef PRIi64
|
||||
#undef PRIo64
|
||||
#undef PRIu64
|
||||
#undef PRIx64
|
||||
#undef PRIX64
|
||||
#define PRId64 "lld"
|
||||
#define PRIi64 "lli"
|
||||
#define PRIo64 "llo"
|
||||
#define PRIu64 "llu"
|
||||
#define PRIx64 "llx"
|
||||
#define PRIX64 "llX"
|
||||
#endif
|
||||
|
||||
//================================== GLOBALS =================================*/
|
||||
//byte g_str_buf[1024];
|
||||
byte* g_str_buf;
|
||||
int load_so(byteptr);
|
||||
void reload_so();
|
||||
void _vinit(int ___argc, voidptr ___argv);
|
||||
void _vcleanup();
|
||||
#define sigaction_size sizeof(sigaction);
|
||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||
|
||||
'
|
||||
c_wyhash = '
|
||||
// ============== wyhash ==============
|
||||
#ifndef wyhash_final_version_3
|
||||
#define wyhash_final_version_3
|
||||
@ -363,7 +326,6 @@ void _vcleanup();
|
||||
|
||||
//includes
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_umul128)
|
||||
@ -527,15 +489,215 @@ static inline void make_secret(uint64_t seed, uint64_t *secret){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
'
|
||||
c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
||||
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
||||
// `"" s` is used to enforce a string literal argument
|
||||
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||
// take the address of an rvalue
|
||||
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
||||
// copy something to the heap
|
||||
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
||||
#define _IN_MAP(val, m) map_exists(m, val)
|
||||
'
|
||||
c_headers =
|
||||
c_helper_macros + c_unsigned_comparison_functions + c_common_macros + r'
|
||||
// c_headers
|
||||
typedef int (*qsort_callback_func)(const void*, const void*);
|
||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define VV_EXPORTED_SYMBOL extern __declspec(dllexport)
|
||||
#define VV_LOCAL_SYMBOL static
|
||||
#else
|
||||
// 4 < gcc < 5 is used by some older Ubuntu LTS and Centos versions,
|
||||
// and does not support __has_attribute(visibility) ...
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && __has_attribute(visibility))
|
||||
#ifdef ARM
|
||||
#define VV_EXPORTED_SYMBOL extern __attribute__((externally_visible,visibility("default")))
|
||||
#else
|
||||
#define VV_EXPORTED_SYMBOL extern __attribute__((visibility("default")))
|
||||
#endif
|
||||
#define VV_LOCAL_SYMBOL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define VV_EXPORTED_SYMBOL extern
|
||||
#define VV_LOCAL_SYMBOL static
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__TINYC__) && defined(__has_include)
|
||||
// tcc does not support has_include properly yet, turn it off completely
|
||||
#undef __has_include
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#if defined __has_include
|
||||
#if __has_include (<execinfo.h>)
|
||||
#include <execinfo.h>
|
||||
#else
|
||||
// Most probably musl OR __ANDROID__ ...
|
||||
int backtrace (void **__array, int __size) { return 0; }
|
||||
char **backtrace_symbols (void *const *__array, int __size){ return 0; }
|
||||
void backtrace_symbols_fd (void *const *__array, int __size, int __fd){}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#include "fns.h"
|
||||
#include <signal.h>
|
||||
#include <stdarg.h> // for va_list
|
||||
|
||||
//================================== GLOBALS =================================*/
|
||||
//byte g_str_buf[1024];
|
||||
byte* g_str_buf;
|
||||
int load_so(byteptr);
|
||||
void reload_so();
|
||||
void _vinit(int ___argc, voidptr ___argv);
|
||||
void _vcleanup();
|
||||
#define sigaction_size sizeof(sigaction);
|
||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||
|
||||
void v_free(voidptr ptr);
|
||||
voidptr memdup(voidptr src, int sz);
|
||||
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||
v_free(ptr);
|
||||
v_free(ptr); // heloe
|
||||
return memdup(src, sz);
|
||||
}
|
||||
'
|
||||
c_builtin_types = '
|
||||
|
||||
|
||||
#if INTPTR_MAX == INT32_MAX
|
||||
#define TARGET_IS_32BIT 1
|
||||
#elif INTPTR_MAX == INT64_MAX
|
||||
#define TARGET_IS_64BIT 1
|
||||
#else
|
||||
#error "The environment is not 32 or 64-bit."
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
|
||||
#define TARGET_ORDER_IS_BIG
|
||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86)
|
||||
#define TARGET_ORDER_IS_LITTLE
|
||||
#else
|
||||
#error "Unknown architecture endianness"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <ctype.h>
|
||||
#include <locale.h> // tolower
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h> // sleep
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) && !defined(_WIN32)
|
||||
#error Cygwin is not supported, please use MinGW or Visual Studio.
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // os__wait uses wait on nix
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WINVER 0x0600
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#ifndef WIN32_FULL
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#include <io.h> // _waccess
|
||||
#include <direct.h> // _wgetcwd
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||
#define _Atomic volatile
|
||||
|
||||
// MSVC cannot parse some things properly
|
||||
#undef EMPTY_STRUCT_DECLARATION
|
||||
#undef OPTION_CAST
|
||||
|
||||
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable
|
||||
#define OPTION_CAST(x)
|
||||
#undef __NOINLINE
|
||||
#undef __IRQHANDLER
|
||||
#define __NOINLINE __declspec(noinline)
|
||||
#define __IRQHANDLER __declspec(naked)
|
||||
|
||||
#include <dbghelp.h>
|
||||
#pragma comment(lib, "Dbghelp")
|
||||
#endif
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#ifndef PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
|
||||
// musl does not have that
|
||||
#define pthread_rwlockattr_setkind_np(a, b)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// g_live_info is used by live.info()
|
||||
static void* g_live_info = NULL;
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__))
|
||||
#undef PRId64
|
||||
#undef PRIi64
|
||||
#undef PRIo64
|
||||
#undef PRIu64
|
||||
#undef PRIx64
|
||||
#undef PRIX64
|
||||
#define PRId64 "lld"
|
||||
#define PRIi64 "lli"
|
||||
#define PRIo64 "llo"
|
||||
#define PRIu64 "llu"
|
||||
#define PRIx64 "llx"
|
||||
#define PRIX64 "llX"
|
||||
#endif
|
||||
|
||||
#ifdef _VFREESTANDING
|
||||
#undef _VFREESTANDING
|
||||
#endif
|
||||
' + c_wyhash
|
||||
c_builtin_types = '
|
||||
//================================== builtin types ================================*/
|
||||
typedef int64_t i64;
|
||||
typedef int16_t i16;
|
||||
@ -569,12 +731,79 @@ typedef bool (*MapEqFn)(voidptr, voidptr);
|
||||
typedef void (*MapCloneFn)(voidptr, voidptr);
|
||||
typedef void (*MapFreeFn)(voidptr);
|
||||
'
|
||||
bare_c_headers = '
|
||||
$c_common_macros
|
||||
bare_c_headers = c_helper_macros + c_unsigned_comparison_functions +
|
||||
c_common_macros +
|
||||
'
|
||||
|
||||
#ifndef exit
|
||||
#define exit(rc) sys_exit(rc)
|
||||
void sys_exit (int);
|
||||
#endif
|
||||
'
|
||||
|
||||
#define stdin 0
|
||||
#define stdout 1
|
||||
#define stderr 2
|
||||
|
||||
#define _VFREESTANDING
|
||||
|
||||
typedef long unsigned int size_t;
|
||||
|
||||
// Memory allocation related headers
|
||||
// void *malloc(int size);
|
||||
byte *calloc(int nitems, int size);
|
||||
byte *realloc(byte *ptr, int size);
|
||||
byte *memcpy(byte *dest, byte *src, int n);
|
||||
byte *memset(byte *s, int c, int n);
|
||||
byte *memmove(byte *dest, byte *src, int n);
|
||||
|
||||
// Backtrace headers
|
||||
int backtrace(void **buffer, int size);
|
||||
char **backtrace_symbols(void *const *buffer, int size);
|
||||
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
|
||||
|
||||
// I/O related headers
|
||||
typedef void FILE;
|
||||
FILE *popen(const char *command, const char *type);
|
||||
int pclose(FILE *stream);
|
||||
int fgetc(FILE *stream);
|
||||
char *fgets(char *s, int size, FILE *stream);
|
||||
int getc(FILE *stream);
|
||||
int getchar(void);
|
||||
int ungetc(int c, FILE *stream);
|
||||
|
||||
|
||||
// char manipulation headers
|
||||
int toupper(int c);
|
||||
int tolower(int c);
|
||||
// int toupper_l(int c, locale_t locale);
|
||||
// int tolower_l(int c, locale_t locale);
|
||||
|
||||
int isatty(int fd);
|
||||
|
||||
// varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(a, b) __builtin_va_start(a, b)
|
||||
#define va_end(a) __builtin_va_end(a)
|
||||
#define va_arg(a, b) __builtin_va_arg(a, b)
|
||||
#define va_copy(a, b) __builtin_va_copy(a, b)
|
||||
|
||||
//================================== GLOBALS =================================*/
|
||||
//byte g_str_buf[1024];
|
||||
byte* g_str_buf;
|
||||
int load_so(byteptr);
|
||||
void reload_so();
|
||||
void _vinit(int ___argc, voidptr ___argv);
|
||||
void _vcleanup();
|
||||
#define sigaction_size sizeof(sigaction);
|
||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||
|
||||
void v_free(voidptr ptr);
|
||||
voidptr memdup(voidptr src, int sz);
|
||||
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||
v_free(ptr); // heloe
|
||||
return memdup(src, sz);
|
||||
}
|
||||
|
||||
' +
|
||||
c_wyhash
|
||||
)
|
||||
|
@ -6,136 +6,7 @@ import v.ast
|
||||
import v.util
|
||||
|
||||
fn (mut g Gen) write_str_fn_definitions() {
|
||||
// _STR function can't be defined in vlib
|
||||
g.writeln('
|
||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||
va_list args;
|
||||
va_start(args, guess);
|
||||
// NB: (*memsize - *nbytes) === how much free space is left at the end of the current buffer refbufp
|
||||
// *memsize === total length of the buffer refbufp
|
||||
// *nbytes === already occupied bytes of buffer refbufp
|
||||
// guess === how many bytes were taken during the current vsnprintf run
|
||||
for(;;) {
|
||||
int remaining_space = *memsize - *nbytes;
|
||||
if (guess < remaining_space) {
|
||||
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
||||
if (guess < remaining_space) { // result did fit into buffer
|
||||
*nbytes += guess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// increase buffer (somewhat exponentially)
|
||||
*memsize += guess + 3 * (*memsize) / 2;
|
||||
#ifdef _VGCBOEHM
|
||||
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||
#else
|
||||
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
||||
#endif
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
string _STR(const char *fmt, int nfmts, ...) {
|
||||
va_list argptr;
|
||||
int memsize = 128;
|
||||
int nbytes = 0;
|
||||
#ifdef _VGCBOEHM
|
||||
char* buf = (char*)GC_MALLOC(memsize);
|
||||
#else
|
||||
char* buf = (char*)malloc(memsize);
|
||||
#endif
|
||||
va_start(argptr, nfmts);
|
||||
for (int i=0; i<nfmts; ++i) {
|
||||
int k = strlen(fmt);
|
||||
bool is_fspec = false;
|
||||
for (int j=0; j<k; ++j) {
|
||||
if (fmt[j] == \'%\') {
|
||||
j++;
|
||||
if (fmt[j] != \'%\') {
|
||||
is_fspec = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_fspec) {
|
||||
char f = fmt[k-1];
|
||||
char fup = f & 0xdf; // toupper
|
||||
bool l = fmt[k-2] == \'l\';
|
||||
bool ll = l && fmt[k-3] == \'l\';
|
||||
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
||||
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
||||
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
||||
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
||||
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
||||
} else if (f == \'p\') {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
||||
} else if (f == \'C\') { // a C string
|
||||
char* sptr = va_arg(argptr, char*);
|
||||
char* fmt_no_c = (char*)v_malloc(k+4);
|
||||
memcpy(fmt_no_c, fmt, k);
|
||||
fmt_no_c[k-2]=\'C\';
|
||||
fmt_no_c[k-1]=\'"\';
|
||||
fmt_no_c[k]=\'%\';
|
||||
fmt_no_c[k+1]=\'s\';
|
||||
fmt_no_c[k+2]=\'"\';
|
||||
fmt_no_c[k+3]=0;
|
||||
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
||||
v_free(fmt_no_c);
|
||||
} else if (f == \'s\') { // v string
|
||||
string s = va_arg(argptr, string);
|
||||
if (fmt[k-4] == \'*\') { // %*.*s
|
||||
int fwidth = va_arg(argptr, int);
|
||||
if (fwidth < 0)
|
||||
fwidth -= (s.len - utf8_str_visible_length(s));
|
||||
else
|
||||
fwidth += (s.len - utf8_str_visible_length(s));
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, fwidth, s.len, s.str);
|
||||
} else { // %.*s
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
||||
}
|
||||
} else {
|
||||
//v_panic(tos3(\'Invaid format specifier\'));
|
||||
}
|
||||
} else {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
||||
}
|
||||
fmt += k+1;
|
||||
}
|
||||
va_end(argptr);
|
||||
buf[nbytes] = 0;
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts(\'_STR:\');
|
||||
puts(buf);
|
||||
#endif
|
||||
|
||||
#if _VAUTOFREE
|
||||
//g_cur_str = (byteptr)buf;
|
||||
#endif
|
||||
return tos2((byteptr)buf);
|
||||
}
|
||||
|
||||
string _STR_TMP(const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
size_t len = vsnprintf(0, 0, fmt, argptr) + 1;
|
||||
va_end(argptr);
|
||||
va_start(argptr, fmt);
|
||||
vsprintf((char *)g_str_buf, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts(\'_STR_TMP:\');
|
||||
//puts(g_str_buf);
|
||||
#endif
|
||||
string res = tos(g_str_buf, len);
|
||||
res.is_lit = 1;
|
||||
return res;
|
||||
|
||||
} // endof _STR_TMP
|
||||
|
||||
')
|
||||
g.writeln(c_str_fn_defs)
|
||||
}
|
||||
|
||||
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
||||
|
@ -916,6 +916,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||
|
||||
mut args := []ast.AsmArg{}
|
||||
args_loop: for {
|
||||
if p.prev_tok.position().line_nr < p.tok.position().line_nr {
|
||||
break
|
||||
}
|
||||
match p.tok.kind {
|
||||
.name {
|
||||
args << p.reg_or_alias()
|
||||
@ -976,6 +979,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||
} else {
|
||||
break
|
||||
}
|
||||
// if p.prev_tok.position().line_nr < p.tok.position().line_nr {
|
||||
// break
|
||||
// }
|
||||
}
|
||||
mut comments := []ast.Comment{}
|
||||
for p.tok.kind == .comment {
|
||||
|
@ -596,6 +596,9 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
||||
res.path += '.v'
|
||||
}
|
||||
}
|
||||
if !res.is_bare && res.bare_builtin_dir != '' {
|
||||
eprintln('`-bare-builtin-dir` must be used with `-freestanding`')
|
||||
}
|
||||
if command == 'build-module' {
|
||||
res.build_mode = .build_module
|
||||
res.path = args[command_pos + 1]
|
||||
|
@ -8,9 +8,6 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
|
||||
files.sort()
|
||||
mut all_v_files := []string{}
|
||||
for file in files {
|
||||
if prefs.is_bare && os.join_path(dir, file).ends_with('/vlib/builtin/builtin_nix.c.v') {
|
||||
continue
|
||||
}
|
||||
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
||||
continue
|
||||
}
|
||||
@ -123,22 +120,22 @@ pub fn (prefs &Preferences) should_compile_c(file string) bool {
|
||||
// Probably something like `a.js.v`.
|
||||
return false
|
||||
}
|
||||
if prefs.is_bare && file.ends_with('.freestanding.v') {
|
||||
return true
|
||||
}
|
||||
if prefs.os == .all {
|
||||
return true
|
||||
}
|
||||
if !prefs.is_bare && file.ends_with('.freestanding.v') {
|
||||
if prefs.backend != .x64 && file.ends_with('_x64.v') {
|
||||
return false
|
||||
}
|
||||
if (file.ends_with('_windows.c.v') || file.ends_with('_windows.v')) && prefs.os != .windows {
|
||||
if prefs.os != .windows && (file.ends_with('_windows.c.v') || file.ends_with('_windows.v')) {
|
||||
return false
|
||||
}
|
||||
if (file.ends_with('_linux.c.v') || file.ends_with('_linux.v')) && prefs.os != .linux {
|
||||
if prefs.os != .linux && (file.ends_with('_linux.c.v') || file.ends_with('_linux.v')) {
|
||||
return false
|
||||
}
|
||||
if (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')) && prefs.os != .macos {
|
||||
return false
|
||||
}
|
||||
if (file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) && prefs.os != .macos {
|
||||
if prefs.os != .macos && (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')) {
|
||||
return false
|
||||
}
|
||||
if (file.ends_with('_ios.c.v') || file.ends_with('_ios.v')) && prefs.os != .ios {
|
||||
@ -147,25 +144,28 @@ pub fn (prefs &Preferences) should_compile_c(file string) bool {
|
||||
if file.ends_with('_nix.c.v') && prefs.os == .windows {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_android.c.v') && prefs.os != .android {
|
||||
if prefs.os != .macos && (file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_freebsd.c.v') && prefs.os != .freebsd {
|
||||
if prefs.os == .windows && file.ends_with('_nix.c.v') {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_openbsd.c.v') && prefs.os != .openbsd {
|
||||
if prefs.os != .android && file.ends_with('_android.c.v') {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_netbsd.c.v') && prefs.os != .netbsd {
|
||||
if prefs.os != .freebsd && file.ends_with('_freebsd.c.v') {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_dragonfly.c.v') && prefs.os != .dragonfly {
|
||||
if prefs.os != .openbsd && file.ends_with('_openbsd.c.v') {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_solaris.c.v') && prefs.os != .solaris {
|
||||
if prefs.os != .netbsd && file.ends_with('_netbsd.c.v') {
|
||||
return false
|
||||
}
|
||||
if file.ends_with('_x64.v') && prefs.backend != .x64 {
|
||||
if prefs.os != .dragonfly && file.ends_with('_dragonfly.c.v') {
|
||||
return false
|
||||
}
|
||||
if prefs.os != .solaris && file.ends_with('_solaris.c.v') {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
Loading…
Reference in New Issue
Block a user