ref: ddb327c92ebe3f96c5c816ec61996440551de401
dir: /lib/std/dial+plan9.myr/
use sys use "alloc" use "die" use "fmt" use "option" use "pathjoin" use "result" use "sleq" use "strfind" use "strstrip" use "syswrap" use "utf" pkg std = const dial : (dialstr : byte[:] -> result(fd, byte[:])) ;; const Maxpath = 512 const dial = {str var netdir, proto, rem (netdir, proto, rem) = parsedial(str) if netdir.len != 0 -> csdial(netdir, proto, rem) ;; match csdial("/net", proto, rem) | `Ok fd: -> `Ok fd | `Err m: -> csdial("/net.alt", proto, rem) ;; } const csdial = {netdir, proto, rem var dir, clone, addr, csaddr var ret, csfd, n var buf : byte[Maxpath] /* Try using the connection server */ dir = fmt("{}/cs", netdir) match open(dir, Ordwr) | `Err e: clone = fmt("{}/{}/clone", netdir, proto) match call(clone, rem, netdir) | `Ok fd: std.slfree(clone) -> `Ok fd | `Err err: std.slfree(clone) -> `Err "unable to dial without cs" ;; | `Ok fd: csfd = fd ;; slfree(dir) csaddr = fmt("{}!{}", proto, rem) match write(csfd, csaddr) | `Err m: close(csfd) -> `Err "couldn't blah cs" | `Ok _: /* nothing */ ;; slfree(csaddr) seek(csfd, 0, 0) while true match read(csfd, buf[:]) | `std.Ok _: | `std.Err e: break ;; match strfind(buf[:n], " ") | `None: continue | `Some i: clone = buf[:i] addr = buf[i+1:n] ;; match call(clone, addr, netdir) | `Ok fd: break | `Err _: /* nothing */ ;; ;; close(csfd) if ret < 0 -> `Err "unable to dial" ;; -> `Ok ret } const call : (a : byte[:], b : byte[:], c : byte[:] -> result(fd, byte[:])) = {clone, addr, netdir var namebuf : byte[Maxpath] var databuf : byte[Maxpath] var name, base, dpath var cfd, datafd var c, n datafd = `Err "didn't even try to open shit" c = nsclonestr(clone, netdir) match open(c, Ordwr) | `Err e: goto cleanup | `Ok fd: cfd = fd ;; match read(cfd, namebuf[:]) | `Ok fd: /* nothing */ | `Err m: goto cleanup ;; fput(cfd, "connect {}", addr) name = strstrip(namebuf[:n]) match strrfind(c, "/") | `None: die("there should be a '/' here\n") | `Some i: base = c[:i] ;; dpath = bfmt(databuf[:], "{}/{}/data", base, name) match open(dpath, Ordwr) | `Ok fd: datafd = `Ok fd | `Err m: datafd = `Err "could not open data" ;; :cleanup close(cfd) slfree(c) -> datafd } const nsclonestr = {clone, netdir if decode(clone) == '#' || decode(clone) == '/' match std.strfind(clone[1:], "/") | `Some i: clone = clone[i+1:] | `None: /* nothing */ ;; ;; -> pathcat(netdir, clone) } const parsedial = {str var netdir, proto, rem, hd, tl netdir="" proto = "" rem = "" match strfind(str, "!") | `None: proto = "net" rem = str | `Some sep: hd = str[:sep] tl = str[sep+1:] if decode(hd) == '#' || decode(hd) == '/' match strrfind(hd, "/") | `Some idx: netdir = hd[:idx] proto = hd[idx+1:] | `None: netdir = "" proto = hd ;; else netdir = "" proto = hd ;; rem = tl ;; -> (netdir, proto, rem) }