Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,230 @@
|
||||
module builtin
|
||||
|
||||
fn C.setvbuf(fstream &C.FILE, buffer &char, mode i32, size usize) i32
|
||||
|
||||
// set_stream_unbuffered switches a stdio stream to unbuffered mode without using the
|
||||
// deprecated `setbuf` API on Windows toolchains.
|
||||
@[unsafe]
|
||||
fn set_stream_unbuffered(stream &C.FILE) {
|
||||
C.setvbuf(stream, &char(nil), C._IONBF, usize(0))
|
||||
}
|
||||
|
||||
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
||||
@[if !noeprintln ?]
|
||||
pub fn eprintln(s string) {
|
||||
$if builtin_print_use_fprintf ? {
|
||||
C.fprintf(C.stderr, c'%.*s\n', s.len, s.str)
|
||||
return
|
||||
}
|
||||
$if freestanding {
|
||||
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||
bare_eprint(s.str, u64(s.len))
|
||||
bare_eprint(c'\n', 1)
|
||||
} $else $if ios {
|
||||
C.WrappedNSLog(s.str)
|
||||
} $else {
|
||||
flush_stdout()
|
||||
flush_stderr()
|
||||
// eprintln is used in panics, so it should not fail at all
|
||||
$if android && !termux {
|
||||
C.android_print(C.stderr, c'%.*s\n', s.len, s.str)
|
||||
}
|
||||
_writeln_to_fd(2, s)
|
||||
flush_stderr()
|
||||
}
|
||||
}
|
||||
|
||||
// eprint prints a message to stderr. Both stderr and stdout are flushed.
|
||||
@[if !noeprintln ?]
|
||||
pub fn eprint(s string) {
|
||||
$if builtin_print_use_fprintf ? {
|
||||
C.fprintf(C.stderr, c'%.*s', s.len, s.str)
|
||||
return
|
||||
}
|
||||
$if freestanding {
|
||||
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||
bare_eprint(s.str, u64(s.len))
|
||||
} $else $if ios {
|
||||
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
||||
C.WrappedNSLog(s.str)
|
||||
} $else {
|
||||
flush_stdout()
|
||||
flush_stderr()
|
||||
$if android && !termux {
|
||||
C.android_print(C.stderr, c'%.*s', s.len, s.str)
|
||||
}
|
||||
_write_buf_to_fd(2, s.str, s.len)
|
||||
flush_stderr()
|
||||
}
|
||||
}
|
||||
|
||||
// flush_stdout flushes the stdout buffer, ensuring all remaining data is written.
|
||||
// See also unbuffer_stdout() .
|
||||
pub fn flush_stdout() {
|
||||
$if v2_native_windows_pe_minimal ? {
|
||||
return
|
||||
} $else $if freestanding {
|
||||
not_implemented := 'flush_stdout is not implemented\n'
|
||||
bare_eprint(not_implemented.str, u64(not_implemented.len))
|
||||
} $else $if builtin_write_buf_to_fd_should_use_c_write ? {
|
||||
// Native backends do not reliably resolve C.stdout/C.stderr data symbols.
|
||||
// Flush all libc output streams without referencing those globals directly.
|
||||
C.fflush(unsafe { nil })
|
||||
} $else {
|
||||
C.fflush(C.stdout)
|
||||
}
|
||||
}
|
||||
|
||||
// flush_stderr flushes the stderr buffer, ensuring all remaining data is written.
|
||||
pub fn flush_stderr() {
|
||||
$if v2_native_windows_pe_minimal ? {
|
||||
return
|
||||
} $else $if freestanding {
|
||||
not_implemented := 'flush_stderr is not implemented\n'
|
||||
bare_eprint(not_implemented.str, u64(not_implemented.len))
|
||||
} $else $if builtin_write_buf_to_fd_should_use_c_write ? {
|
||||
// Native backends do not reliably resolve C.stdout/C.stderr data symbols.
|
||||
// Flush all libc output streams without referencing those globals directly.
|
||||
C.fflush(unsafe { nil })
|
||||
} $else {
|
||||
C.fflush(C.stderr)
|
||||
}
|
||||
}
|
||||
|
||||
// unbuffer_stdout will turn off the default buffering done for stdout.
|
||||
// It will affect all consequent print and println calls, effectively making them behave like
|
||||
// eprint and eprintln do. It is useful for programs, that want to produce progress bars, without
|
||||
// cluttering your code with a flush_stdout() call after every print() call. It is also useful for
|
||||
// programs (sensors), that produce small chunks of output, that you want to be able to process
|
||||
// immediately.
|
||||
// Note 1: if used, *it should be called at the start of your program*, before using
|
||||
// print or println().
|
||||
// Note 2: most libc implementations, have logic that use line buffering for stdout, when the output
|
||||
// stream is connected to an interactive device, like a terminal, and otherwise fully buffer it,
|
||||
// which is good for the output performance for programs that can produce a lot of output (like
|
||||
// filters, or cat etc), but bad for latency. V uses unbuffered stdout by default on the common C
|
||||
// backends, to make print and println visible immediately even when stdout is redirected.
|
||||
// See https://www.gnu.org/software/libc/manual/html_node/Buffering-Concepts.html .
|
||||
// See https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05 .
|
||||
pub fn unbuffer_stdout() {
|
||||
$if vinix {
|
||||
return
|
||||
} $else $if freestanding {
|
||||
not_implemented := 'unbuffer_stdout is not implemented\n'
|
||||
bare_eprint(not_implemented.str, u64(not_implemented.len))
|
||||
} $else $if builtin_write_buf_to_fd_should_use_c_write ? {
|
||||
// Native backends already print via write(), so there is no stdio buffer to adjust here.
|
||||
return
|
||||
} $else {
|
||||
unsafe { set_stream_unbuffered(C.stdout) }
|
||||
}
|
||||
}
|
||||
|
||||
// print prints a message to stdout.
|
||||
@[manualfree]
|
||||
pub fn print(s string) {
|
||||
$if builtin_print_use_fprintf ? {
|
||||
C.fprintf(C.stdout, c'%.*s', s.len, s.str)
|
||||
return
|
||||
}
|
||||
$if android && !termux {
|
||||
C.android_print(C.stdout, c'%.*s\n', s.len, s.str)
|
||||
} $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 {
|
||||
_write_buf_to_fd(1, s.str, s.len)
|
||||
}
|
||||
}
|
||||
|
||||
// println prints a message with a line end, to stdout.
|
||||
@[if !noprintln ?; manualfree]
|
||||
pub fn println(s string) {
|
||||
$if builtin_print_use_fprintf ? {
|
||||
C.fprintf(C.stdout, c'%.*s\n', s.len, s.str)
|
||||
return
|
||||
}
|
||||
$if android && !termux {
|
||||
C.android_print(C.stdout, c'%.*s\n', s.len, s.str)
|
||||
return
|
||||
} $else $if ios {
|
||||
C.WrappedNSLog(s.str)
|
||||
return
|
||||
} $else $if freestanding {
|
||||
bare_print(s.str, u64(s.len))
|
||||
bare_print(c'\n', 1)
|
||||
return
|
||||
} $else {
|
||||
_writeln_to_fd(1, s)
|
||||
}
|
||||
}
|
||||
|
||||
@[manualfree]
|
||||
fn _writeln_to_fd(fd int, s string) {
|
||||
$if builtin_writeln_should_write_at_once ? {
|
||||
unsafe {
|
||||
buf_len := s.len + 1 // space for \n
|
||||
mut buf := malloc(buf_len)
|
||||
C.memcpy(buf, s.str, s.len)
|
||||
buf[s.len] = `\n`
|
||||
_write_buf_to_fd(fd, buf, buf_len)
|
||||
free(buf)
|
||||
}
|
||||
} $else {
|
||||
lf := u8(`\n`)
|
||||
_write_buf_to_fd(fd, s.str, s.len)
|
||||
_write_buf_to_fd(fd, &lf, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@[manualfree]
|
||||
fn _write_buf_to_fd(fd int, buf &u8, buf_len int) {
|
||||
if buf_len <= 0 {
|
||||
return
|
||||
}
|
||||
$if windows {
|
||||
$if v2_native_windows_pe_minimal ? {
|
||||
write_buf_to_fd_kernel32_or_exit(fd, buf, buf_len)
|
||||
} $else {
|
||||
write_buf_to_fd_windows_non_minimal(fd, buf, buf_len)
|
||||
}
|
||||
} $else {
|
||||
mut ptr := unsafe { buf }
|
||||
mut remaining_bytes := isize(buf_len)
|
||||
mut x := isize(0)
|
||||
$if freestanding || vinix || builtin_write_buf_to_fd_should_use_c_write ? {
|
||||
// Flush any pending libc stdio output (from C.puts, C.putchar, etc.)
|
||||
// before writing directly via write() syscall to prevent output reordering.
|
||||
C.fflush(unsafe { nil })
|
||||
unsafe {
|
||||
for remaining_bytes > 0 {
|
||||
x = C.write(fd, ptr, remaining_bytes)
|
||||
if x <= 0 {
|
||||
// Detached/invalid stdio must not trap the process in an infinite loop.
|
||||
break
|
||||
}
|
||||
ptr += x
|
||||
remaining_bytes -= x
|
||||
}
|
||||
}
|
||||
} $else {
|
||||
mut stream := voidptr(C.stdout)
|
||||
if fd == 2 {
|
||||
stream = voidptr(C.stderr)
|
||||
}
|
||||
unsafe {
|
||||
for remaining_bytes > 0 {
|
||||
x = isize(C.fwrite(ptr, 1, remaining_bytes, stream))
|
||||
if x <= 0 {
|
||||
// GUI programs on Windows may not have a writable stdout/stderr stream.
|
||||
break
|
||||
}
|
||||
ptr += x
|
||||
remaining_bytes -= x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user