xref: /inferno-os/appl/cmd/plumb.b (revision 3555c65fdd2b7ff06f1847e174486888d459748c)
1implement Plumb;
2
3include "sys.m";
4	sys: Sys;
5
6include "draw.m";
7
8include "arg.m";
9
10include "plumbmsg.m";
11	plumbmsg: Plumbmsg;
12	Msg, Attr: import plumbmsg;
13
14include "workdir.m";
15	workdir: Workdir;
16
17Plumb: module
18{
19	init:	fn(nil: ref Draw->Context, nil: list of string);
20};
21
22init(nil: ref Draw->Context, args: list of string)
23{
24	sys = load Sys Sys->PATH;
25	plumbmsg = load Plumbmsg Plumbmsg->PATH;
26	if(plumbmsg == nil)
27		nomod(Plumbmsg->PATH);
28	workdir = load Workdir Workdir->PATH;
29	if(workdir == nil)
30		nomod(Workdir->PATH);
31
32	if(plumbmsg->init(1, nil, 0) < 0)
33		err(sys->sprint("can't connect to plumb: %r"));
34
35	attrs: list of ref Attr;
36	input := 0;
37	m := ref Msg("plumb", nil, workdir->init(), "text", nil, nil);
38	arg := load Arg Arg->PATH;
39	arg->init(args);
40	arg->setusage("plumb [-s src] [-d dest] [-w wdir] [-t type] [-a name val] -i | ... data ...");
41	while((c := arg->opt()) != 0)
42		case c {
43		's' =>
44			m.src = arg->earg();
45		'd' =>
46			m.dst = arg->earg();
47		'w' or 'D' =>
48			m.dir = arg->earg();
49		'i' =>
50			input++;
51		't' or 'k'=>
52			m.kind = arg->arg();
53		'a' =>
54			name := arg->earg();
55			val := arg->earg();
56			attrs = tack(attrs, ref Attr(name, val));
57		* =>
58			arg->usage();
59		}
60	args = arg->argv();
61	if(input && args != nil || !input && args == nil)
62		arg->usage();
63	arg = nil;
64
65	if(input){
66		m.data = gather(sys->fildes(0));
67		(notfound, nil) := plumbmsg->lookup(plumbmsg->string2attrs(m.attr), "action");
68		if(notfound)
69			tack(attrs, ref Attr("action", "showdata"));
70		m.attr = plumbmsg->attrs2string(attrs);
71		if(m.send() < 0)
72			err(sys->sprint("can't send message: %r"));
73		exit;
74	}
75
76	nb := 0;
77	for(a := args; a != nil; a = tl a)
78		nb += len array of byte hd a;
79	nb += len args;
80	buf := array[nb] of byte;
81	nb = 0;
82	for(a = args; a != nil; a = tl a){
83		b := array of byte hd a;
84		buf[nb++] = byte ' ';
85		buf[nb:] = b;
86		nb += len b;
87	}
88	m.data = buf[1:];
89	m.attr = plumbmsg->attrs2string(attrs);
90	if(m.send() < 0)
91		err(sys->sprint("can't plumb message: %r"));
92}
93
94gather(fd: ref Sys->FD): array of byte
95{
96	Chunk: con 8192;	# arbitrary
97	ndata := 0;
98	buf := array[Chunk] of byte;
99	while((n := sys->read(fd, buf[ndata:], len buf - ndata)) > 0){
100		ndata += n;
101		if(len buf - ndata < Chunk){
102			t := array[len buf+Chunk] of byte;
103			t[0:] = buf[0: ndata];
104			buf = t;
105		}
106	}
107	if(n < 0)
108		err(sys->sprint("error reading input: %r"));
109	return buf[0: ndata];
110}
111
112tack(l: list of ref Attr, v: ref Attr): list of ref Attr
113{
114	if(l == nil)
115		return v :: nil;
116	return hd l :: tack(tl l, v);
117}
118
119nomod(m: string)
120{
121	err(sys->sprint("can't load %s: %r", m));
122}
123
124err(s: string)
125{
126	sys->fprint(sys->fildes(2), "plumb: %s\n", s);
127	raise "fail:error";
128}
129