The outside world
A program that cannot be told anything is not much use. std/os has the
arguments and the environment:
import "std/io"import "std/os"import "std/strings"
func main() !int { mut room := [8]string{} args := os.Args(room[..])
mut port u64 = 8080 if args.len > 1 { port = try strings.ParseU64(args[1]) }
host := os.EnvOr("HOST", "127.0.0.1") try io.Printf("listening on {}:{}\n", host, port) return 0}Args fills an array you hand it rather than allocating one — the same rule as
everywhere else in the standard library, and the reason os.Args() takes an
argument at all. args[0] is the program’s own name, as in C. Env gives back
an optional, because a variable that is set to nothing is not the same as one
that is not set:
if level := os.Env("LOG_LEVEL") { try io.Printf("logging at {}\n", level)}std/fs reads and writes files:
import "std/fs"import "std/io"import "std/mem"
func main() !int { mut backing := [65536]u8{} mut arena := mem.NewArena(backing[..])
try fs.WriteAll("/tmp/greeting", []u8("hello\n")) back := try fs.ReadAll("/tmp/greeting", &arena) try io.Print(string(back)) try fs.Remove("/tmp/greeting") return 0}fs.Size gives an optional, because a path that is not there has no size and a
number would be a lie. fs.ReadStdin takes whatever was piped in.
std/os also has signals, which is how a server is asked to stop:
try os.Catch(os.Signal.Terminate)sig := try os.WaitSignal()WaitSignal is an ordinary wait — it costs a stack and not a thread — so it
sits in a task beside the work it is going to interrupt.
std/time has the clocks. Two of them: Now reads a clock that only counts
forward, for measuring, and Unix reads the wall clock, for stamping.
import "std/time"
start := time.Now()work()took := time.Since(start)try io.Printf("took {}ms\n", took.AsMillis())A Duration is a length of time rather than a bare number, so a function that
takes one cannot be handed seconds where it wanted milliseconds:
time.Sleep(time.Millis(250))try conn.SetTimeout(time.Seconds(5))A method can be called on a value that has no name yet —
time.Since(start).AsMillis() — unless it writes through its receiver: then
the change would have nowhere to go, and the compiler asks you to bind the value
first.
Talking to C
Section titled “Talking to C”Sword calls C directly. extern declares a C function by its own name, and the
call is an ordinary call:
extern func abs(x i32) i32
func main() int { return int(abs(-42))}Only scalars cross — numbers, bool, raw pointers — because a string or a
slice is two words to Sword and a pointer to C, so you pass .ptr and .len.
When the function lives in a library, name the library after extern, the way
-l would, and it is linked without anyone mentioning it on the command line:
extern "z" func zlibVersion() [*]u8It is linked dynamically unless you build with shield --static, which takes
it from libz.a instead.
std/c gives C’s types their C names, so a declaration reads like the header
it came from, and os.Errno reads what a failing call left behind:
import "std/c"import "std/io"import "std/os"
extern func close(fd c.Int) c.Int
func main() !int { if close(-1) < 0 { try io.Printf("errno {}\n", os.Errno()) } return 0}Read errno straight after the call. It belongs to the thread, and a task that waits for anything may carry on from another one.
A C function can be a value too. Its type is extern func(...), kept apart
from func(...), which only ever points at Sword code. A Sword function can be
handed to C wherever C expects one — this is how qsort gets its comparison:
extern func qsort(base [*]u8, n u64, size u64, less extern func([*]u8, [*]u8) i32)A function that only some machines have is declared extern weak. The program
starts either way, and the name is an optional to check before calling:
extern weak func getentropy(buf [*]u8, n u64) i32
if fill := getentropy { // here, fill is the function}And a library the program finds while it runs — a plugin — is opened with
std/dl, which hands back addresses for you to say the type of:
mut ld := dl.NewLoader()lib := ld.Open("libplugin.so") catch { try io.Printf("{}\n", ld.Why()) return 1}start := extern func() i32(try ld.Symbol(lib, "plugin_start"))