[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

p.b



I ported the plan9 p (paginate) command to inferno.  Accepts the
-number option and understands the '!' commmand to pass a command
to sh (thanks to "time.b"!).

# 
implement p;

include "sys.m"; 
include "draw.m";
include "lib.m";
include "bufio.m";
include "sh.m";

Context:  import Draw;
FD:       import Sys;

stdin, stderr, stdout, waitfd: ref FD;
sys: Sys;
str: String;
bufmod: Bufio;
Iobuf: import bufmod;
outb, cons: ref Iobuf;

nlines := 22;
progname: string;

p: module
{
    init:  fn(ctxt:  ref Context, argv:  list of string);
};


init(nil: ref Context, argv:  list of string)
{
    sys     = load Sys Sys->PATH;
    bufmod  = load Bufio Bufio->PATH;
    str     = load String String->PATH;

    stdout = sys->fildes(1);
    stderr = sys->fildes(2);
    stdin  = sys->fildes(0);

    progname = str->take(hd argv, "^.");        # strip off ".dis"
    argv = tl argv;
    if(argv != nil){
        s := hd argv;
        if(s[0] == '-' && len s >= 2){          # not "-" for stdin
                (x, y) := str->toint(s[1:],10);
                if(y == "" && x > 0)
                    nlines = x;
                else
                    usage();
                argv = tl argv;
        }
    }
    if(argv == nil)
        argv = "stdin"::nil;
    # do these once
    outb = bufmod->fopen(stdout, bufmod->OWRITE);
    if(outb == nil){
        sys->fprint(stderr, "%s fatal: can't open stdout, %r\n",
progname);
        return;
    }
    cons = bufmod->open("/dev/cons", bufmod->OREAD);
    if(cons == nil){
        sys->fprint(stderr, "%s fatal: can't open /dev/cons, %r\n",
progname);
        return;
    }
    
    while(argv != nil){
        file := hd argv;
        if(file == "-")
            file = "stdin";
        page(file);
        argv = tl argv;
    }
}

usage()
{
    sys->fprint(stderr, "Usage: %s [-number] [file...]\n", progname);
    exit;
}

page(file : string)
{
    inb: ref Iobuf;
    line, cmdline: string;
    nl: int;

    if(file == "stdin") 
        inb = bufmod->fopen(stdin, bufmod->OREAD);
    else
        inb = bufmod->open(file, bufmod->OREAD);
    if(inb == nil){
        sys->fprint(stderr,"%s can't open %s, %r\n", progname, file);
        return;
    }
    nl = nlines;
    while((line = inb.gets('\n')) != nil){
        outb.puts(line);        
        nl--;
        if(nl == 0){
            outb.flush();
            nl = nlines;
            for(;;){
                cmdline = cons.gets('\n');
                if(cmdline == nil || cmdline[0] == 'q') # catch ^d
                    exit;
                else if(cmdline[0] == '!') 
                    doCommand(cmdline[1:]);
                else
                    break;
            }
        }
    }
    outb.flush();   
    #* I/O check needed here
}

doCommand(cmdline: string)
{
    err : string;
    
    (argc, arglist) := sys->tokenize(cmdline, " \t\n");
    if(argc == 0)
        return;
    cname := hd arglist;

    # --------------------------------------------------------
    # Taken, "with the lofty joy thy speech infuses into me"
    # (Par. Can. 8, Longfellow), from time.b
    #---------------------------------------------------------
    
    if(len cname < 4 || cname[len cname-4:] != ".dis")
        cname += ".dis";
    arglist = tl arglist;
    
    c := load Command cname;
    if(c == nil){
        err = sys->sprint("%r");
        if(err == "file does not exist"){
            c = load Command "/dis/" + cname;
            if (c == nil)
                err = sys->sprint("%r");
        }
    }
    if(c == nil){
        sys->fprint(stderr, "%s: %s - %s\n", progname, cname, err);
        return;
    }
    
    waitfd = sys->open("#p/"+string sys->pctl(0, nil)+"/wait",
sys->OREAD);
    if(waitfd == nil){
        sys->fprint(stderr, "time: open wait: %r\n");
        return;
    }
    
    pidc := chan of int;
    spawn reallyDoCommand(c, pidc, cname::arglist);   
    waitfor(<-pidc);
}
    
reallyDoCommand(c: Command, pidc: chan of int, arglist: list of string)
{
    pidc <-= sys->pctl(sys->FORKNS, nil);
    c->init(nil, arglist);
}

# more lofty joy
waitfor(pid: int)
{
    buf := array[sys->WAITLEN] of byte;
    status := "";
    for(;;){
        n := sys->read(waitfd, buf, len buf);
        if(n < 0) {
            sys->fprint(stderr, "sh: read wait: %r\n");
            return;
        }
        status = string buf[0:n];
        if(status[len status-1] != ':')
            sys->fprint(stderr, "%s\n", status);
        who := int status;
        if(who != 0) {
            if(who == pid)
                return;
        }
    }
}