include "sh.m"; cmd := load Command path;
PATH: con "/dis/sh.dis"; init: fn(ctxt: ref Draw->Context, args: list of string);
Every command must have an init function with the signature shown above. Note that Limbo rules allow a module to expose a larger interface for use by other applications (see for instance sh(2)); provided it includes the form of init shown above, the module can also be invoked as a command.
Ctxt provides the graphics context for a windowing application, which typically passes it to wmlib(2) (eg, to titlebar) or directly to tk(2). It is nil for commands started by the shells.
The arguments to the command are passed as a simple list of strings, args. By convention, the name of the command or the name of its .dis file heads the list.
PATH names the file containing sh(1), (on small systems, this might actually name an instance of tiny(1)) but usually the path name of another command will be given to the Limbo load operator:
include "sh.m";...
cmd := load Command "/dis/date.dis"; cmd->init(nil, "date" :: nil);
In practice more care must be taken when invoking programs. In the example above, the current process executes the body of cmd->init and if that executes exit, raises an exception, or otherwise modifies the state of the process, the caller is affected. The following is more prudent:
child(file: string, args: list of string, pidc: chan of int) { pidc <-= sys->pctl(Sys->NEWFD|Sys->FORKNS|Sys->NEWPGRP, list of {0, 1, 2}); cmd := load Command file; if(cmd == nil){ sys->print("can't load %s: %r\n", file); exit; } cmd->init(nil, args); } parent() { pidc := chan of int; spawn child(disfile, args, pidc); pid := <-pidc; ... }
A new child process runs the command only after using sys-pctl to insulate the caller from untoward changes to its environment. Note the idiomatic use of a channel to return the child's process ID to its parent, which can then if desired use the wait file of prog(3) to watch over the child and wait for its demise. or use the ctl file of prog(3) to dispose of it. Furthermore, any state shared between parent and child can safely be accessed by the child before it sends the ID because the parent is blocked on the receive.
COMMAND(2 ) | Rev: Tue Nov 27 18:20:36 GMT 2007 |