ref: 57c522a6b71132167243a28c58184f70219d069a
dir: /appl/cmd/p.b/
implement P;
# Original by Steve Arons, based on Plan 9 p
include "sys.m";
sys: Sys;
FD: import Sys;
include "draw.m";
include "string.m";
str: String;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "sh.m";
stderr: ref FD;
outb, cons: ref Iobuf;
drawctxt: ref Draw->Context;
nlines := 22; # 1/3rd 66-line nroff page (!)
progname := "p";
P: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
usage()
{
sys->fprint(stderr, "Usage: p [-number] [file...]\n");
raise "fail:usage";
}
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
bufio = load Bufio Bufio->PATH;
if(bufio == nil)
nomod(Bufio->PATH);
str = load String String->PATH;
if(str == nil)
nomod(String->PATH);
sys->pctl(Sys->FORKFD, nil);
drawctxt = ctxt;
stderr = sys->fildes(2);
if((stdout := sys->fildes(1)) != nil)
outb = bufio->fopen(stdout, bufio->OWRITE);
if(outb == nil){
sys->fprint(stderr, "p: can't open stdout: %r\n");
raise "fail:stdout";
}
cons = bufio->open("/dev/cons", bufio->OREAD);
if(cons == nil){
sys->fprint(stderr, "p: can't open /dev/cons: %r\n");
raise "fail:cons";
}
if(argv != nil){
progname = hd argv;
argv = tl argv;
if(argv != nil){
s := hd argv;
if(len s > 1 && s[0] == '-'){
(x, y) := str->toint(s[1:],10);
if(y == "" && x > 0)
nlines = x;
else
usage();
argv = tl argv;
}
}
}
if(argv == nil)
argv = "-" :: nil;
for(; argv != nil; argv = tl argv){
file := hd argv;
fd: ref Sys->FD;
if(file == "-"){
file = "stdin";
fd = sys->fildes(0);
}else
fd = sys->open(file, Sys->OREAD);
if(fd == nil){
sys->fprint(stderr, "%s: can't open %s: %r\n", progname, file);
continue;
}
page(fd);
fd = nil;
}
}
nomod(m: string)
{
sys->fprint(sys->fildes(2), "%s: can't load %s: %r\n", progname, m);
raise "fail:load";
}
page(fd: ref Sys->FD)
{
inb := bufio->fopen(fd, bufio->OREAD);
nl := nlines;
while((line := inb.gets('\n')) != nil){
outb.puts(line);
if(--nl == 0){
outb.flush();
nl = nlines;
pause();
}
}
outb.flush();
}
pause()
{
for(;;){
cmdline := cons.gets('\n');
if(cmdline == nil || cmdline[0] == 'q') # catch ^d
exit;
else if(cmdline[0] == '!') {
done := chan of int;
spawn command(cmdline[1:], done);
<-done;
}else
break;
}
}
command(cmdline: string, done: chan of int)
{
sh := load Sh Sh->PATH;
if(sh == nil) {
sys->fprint(stderr, "%s: can't load %s: %r\n", progname, Sh->PATH);
done <-= 0;
return;
}
sys->pctl(Sys->FORKFD, nil);
sys->dup(cons.fd.fd, 0);
sh->system(drawctxt, cmdline);
done <-= 1;
}