xref: /inferno-os/appl/cmd/mash/history.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Mashbuiltin;
2
3#
4#	"history" builtin, defines:
5#
6
7include	"mash.m";
8include	"mashparse.m";
9
10mashlib:	Mashlib;
11chanfill:	ChanFill;
12
13Env:		import mashlib;
14sys, bufio:	import mashlib;
15
16Iobuf:	import bufio;
17
18Hcmd: adt
19{
20	seek:	int;
21	text:	array of byte;
22};
23
24Reader: adt
25{
26	fid:	int;
27	offset:	int;
28	hint:	int;
29	next:	cyclic ref Reader;
30};
31
32history:	array of ref Hcmd;
33lhist:		int;
34nhist:		int;
35seek:		int;
36readers:	ref Reader;
37eof :=		array[0] of byte;
38
39#
40#	Interface to catch the use as a command.
41#
42init(nil: ref Draw->Context, args: list of string)
43{
44	raise "fail: " + hd args + " not loaded";
45}
46
47#
48#	Used by whatis.
49#
50name(): string
51{
52	return "history";
53}
54
55#
56#	Install commands.
57#
58mashinit(nil: list of string, lib: Mashlib, nil: Mashbuiltin, e: ref Env)
59{
60	mashlib = lib;
61	if (mashlib->histchan != nil)
62		return;
63	mashlib->startserve = 1;
64	nhist = 0;
65	lhist = 256;
66	history = array[lhist] of ref Hcmd;
67	seek = 0;
68	(f, c) := e.servefile(mashlib->HISTF);
69	spawn servehist(f, c);
70	(f, c) = e.servefile(mashlib->MASHF);
71	spawn servemash(f, c);
72}
73
74mashcmd(nil: ref Env, nil: list of string)
75{
76}
77
78addhist(b: array of byte)
79{
80	if (nhist == lhist) {
81		n := 3 * nhist / 4;
82		part := history[:n];
83		part[:] = history[nhist - n:];
84		nhist = n;
85	}
86	history[nhist] = ref Hcmd(seek, b);
87	nhist++;
88	seek += len b;
89}
90
91getfid(fid: int, del: int): ref Reader
92{
93	prev: ref Reader;
94	for (r := readers; r != nil; r = r.next) {
95		if (r.fid == fid) {
96			if (del) {
97				if (prev == nil)
98					readers = r.next;
99				else
100					prev.next = r.next;
101				return nil;
102			}
103			return r;
104		}
105		prev = r;
106	}
107	o := 0;
108	if (nhist > 0)
109		o = history[0].seek;
110	return readers = ref Reader(fid, o, 0, readers);
111}
112
113readhist(off, count, fid: int): (array of byte, string)
114{
115	r := getfid(fid, 0);
116	off += r.offset;
117	if (nhist == 0 || off >= seek)
118		return (eof, nil);
119	i := r.hint;
120	if (i >= nhist)
121		i = nhist - 1;
122	s := history[i].seek;
123	if (off == s) {
124		r.hint = i + 1;
125		return (history[i].text, nil);
126	}
127	if (off > s) {
128		do {
129			if (++i == nhist)
130				break;
131			s = history[i].seek;
132		} while (off >= s);
133		i--;
134	} else {
135		do {
136			if (--i < 0)
137				return (eof, "data truncated");
138			s = history[i].seek;
139		} while (off < s);
140	}
141	r.hint = i + 1;
142	b := history[i].text;
143	if (off != s)
144		b = b[off - s:];
145	return (b, nil);
146}
147
148loadhist(data: array of byte, fid: int, wc: Sys->Rwrite, c: ref Sys->FileIO)
149{
150	in: ref Iobuf;
151	if (chanfill == nil)
152		chanfill = load ChanFill ChanFill->PATH;
153	if (chanfill != nil)
154		in = chanfill->init(data, fid, wc, c, mashlib->bufio);
155	if (in == nil) {
156		in = bufio->sopen(string data);
157		if (in == nil) {
158			wc <-= (0, mashlib->errstr());
159			return;
160		}
161		wc <-= (len data, nil);
162	}
163	while ((s := in.gets('\n')) != nil)
164		addhist(array of byte s);
165	in.close();
166}
167
168servehist(f: string, c: ref Sys->FileIO)
169{
170	mashlib->reap();
171	h := chan of array of byte;
172	mashlib->histchan = h;
173	for (;;) {
174		alt {
175		b := <-h =>
176			addhist(b);
177		(off, count, fid, rc) := <-c.read =>
178			if (rc == nil) {
179				getfid(fid, 1);
180				continue;
181			}
182			rc <-= readhist(off, count, fid);
183		(off, data, fid, wc) := <-c.write =>
184			if (wc != nil)
185				loadhist(data, fid, wc, c);
186		}
187	}
188}
189
190servemash(f: string, c: ref Sys->FileIO)
191{
192	mashlib->reap();
193	for (;;) {
194		alt {
195		(off, count, fid, rc) := <-c.read =>
196			if (rc != nil)
197				rc <-= (nil, "not supported");
198		(off, data, fid, wc) := <-c.write =>
199			if (wc != nil) {
200				wc <-= (len data, nil);
201				if (mashlib->servechan != nil && len data > 0)
202					mashlib->servechan <-= data;
203			}
204		}
205	}
206}
207