xref: /plan9-contrib/sys/src/cmd/sam/rasp.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "sam.h"
2 /*
3  * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,
4  * so they will be scrolled into visibility in the ~~sam~~ window (yuck!).
5  */
6 #define	GROWDATASIZE	50	/* if size is > this, send data with grow */
7 
8 void	rcut(List*, Posn, Posn);
9 int	rterm(List*, Posn);
10 void	rgrow(List*, Posn, Posn);
11 
12 void
13 toterminal(File *f, int toterm)
14 {
15 	Buffer *t = f->transcript;
16 	Posn n, p0, p1, p2, delta = 0, deltacmd = 0;
17 	Range r;
18 	union{
19 		union	Hdr g;
20 		Rune	buf[8+GROWDATASIZE];
21 	}hdr;
22 	Posn growpos, grown;
23 
24 	if(f->rasp == 0)
25 		return;
26 	if(f->marked)
27 		p0 = f->markp+sizeof(Mark)/RUNESIZE;
28 	else
29 		p0 = 0;
30 	grown = 0;
31 	noflush = 1;
32 	SET(growpos);
33 	while(Bread(t, (Rune*)&hdr, sizeof(hdr)/RUNESIZE, p0) > 0){
34 		switch(hdr.g.cs.c){
35 		default:
36 			fprint(2, "char %c %.2ux\n", hdr.g.cs.c, hdr.g.cs.c);
37 			panic("unknown in toterminal");
38 
39 		case 'd':
40 			if(grown){
41 				outTsll(Hgrow, f->tag, growpos, grown);
42 				grown = 0;
43 			}
44 			p1 = hdr.g.cll.l;
45 			p2 = hdr.g.cll.l1;
46 			if(p2 <= p1)
47 				panic("toterminal delete 0");
48 			if(f==cmd && p1<cmdpt){
49 				if(p2 <= cmdpt)
50 					deltacmd -= (p2-p1);
51 				else
52 					deltacmd -= cmdpt-p1;
53 			}
54 			p1 += delta;
55 			p2 += delta;
56 			p0 += sizeof(struct _cll)/RUNESIZE;
57 			if(toterm)
58 				outTsll(Hcut, f->tag, p1, p2-p1);
59 			rcut(f->rasp, p1, p2);
60 			delta -= p2-p1;
61 			break;
62 
63 		case 'f':
64 			if(grown){
65 				outTsll(Hgrow, f->tag, growpos, grown);
66 				grown = 0;
67 			}
68 			n = hdr.g.cs.s;
69 			p0 += sizeof(struct _cs)/RUNESIZE + n;
70 			break;
71 
72 		case 'i':
73 			n = hdr.g.csl.s;
74 			p1 = hdr.g.csl.l;
75 			p0 += sizeof(struct _csl)/RUNESIZE + n;
76 			if(n <= 0)
77 				panic("toterminal insert 0");
78 			if(f==cmd && p1<cmdpt)
79 				deltacmd += n;
80 			p1 += delta;
81 			if(toterm){
82 				if(n>GROWDATASIZE || !rterm(f->rasp, p1)){
83 					rgrow(f->rasp, p1, n);
84 					if(grown && growpos+grown!=p1){
85 						outTsll(Hgrow, f->tag, growpos, grown);
86 						grown = 0;
87 					}
88 					if(grown)
89 						grown += n;
90 					else{
91 						growpos = p1;
92 						grown = n;
93 					}
94 				}else{
95 					Rune *rp;
96 					if(grown){
97 						outTsll(Hgrow, f->tag, growpos, grown);
98 						grown = 0;
99 					}
100 					rp = hdr.buf+sizeof(hdr.g.csl)/RUNESIZE;
101 					rgrow(f->rasp, p1, n);
102 					r = rdata(f->rasp, p1, n);
103 					if(r.p1!=p1 || r.p2!=p1+n)
104 						panic("rdata in toterminal");
105 					outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(rp, n));
106 				}
107 			}else{
108 				rgrow(f->rasp, p1, n);
109 				r = rdata(f->rasp, p1, n);
110 				if(r.p1!=p1 || r.p2!=p1+n)
111 					panic("rdata in toterminal");
112 			}
113 			delta += n;
114 			break;
115 		}
116 	}
117 	if(grown)
118 		outTsll(Hgrow, f->tag, growpos, grown);
119 	if(toterm)
120 		outTs(Hcheck0, f->tag);
121 	outflush();
122 	noflush = 0;
123 	if(f == cmd){
124 		cmdpt += deltacmd+cmdptadv;
125 		cmdptadv = 0;
126 	}
127 }
128 
129 #define	M	0x80000000L
130 #define	P(i)	r->longptr[i]
131 #define	T(i)	(P(i)&M)	/* in terminal */
132 #define	L(i)	(P(i)&~M)	/* length of this piece */
133 
134 void
135 rcut(List *r, Posn p1, Posn p2)
136 {
137 	Posn p, x;
138 	int i;
139 
140 	if(p1 == p2)
141 		panic("rcut 0");
142 	for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
143 		;
144 	if(i == r->nused)
145 		panic("rcut 1");
146 	if(p<p1){	/* chop this piece */
147 		if(p+L(i) < p2){
148 			x = p1-p;
149 			p += L(i);
150 		}else{
151 			x = L(i)-(p2-p1);
152 			p = p2;
153 		}
154 		if(T(i))
155 			P(i) = x|M;
156 		else
157 			P(i) = x;
158 		i++;
159 	}
160 	while(i<r->nused && p+L(i)<=p2){
161 		p += L(i);
162 		dellist(r, i);
163 	}
164 	if(p<p2){
165 		if(i == r->nused)
166 			panic("rcut 2");
167 		x = L(i)-(p2-p);
168 		if(T(i))
169 			P(i) = x|M;
170 		else
171 			P(i) = x;
172 	}
173 	/* can we merge i and i-1 ? */
174 	if(i>0 && i<r->nused && T(i-1)==T(i)){
175 		x = L(i-1)+L(i);
176 		dellist(r, i--);
177 		if(T(i))
178 			P(i)=x|M;
179 		else
180 			P(i)=x;
181 	}
182 }
183 
184 void
185 rgrow(List *r, Posn p1, Posn n)
186 {
187 	Posn p;
188 	int i;
189 
190 	if(n == 0)
191 		panic("rgrow 0");
192 	for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
193 		;
194 	if(i == r->nused){	/* stick on end of file */
195 		if(p!=p1)
196 			panic("rgrow 1");
197 		if(i>0 && !T(i-1))
198 			P(i-1)+=n;
199 		else
200 			inslist(r, i, n);
201 	}else if(!T(i))		/* goes in this empty piece */
202 		P(i)+=n;
203 	else if(p==p1 && i>0 && !T(i-1))	/* special case; simplifies life */
204 		P(i-1)+=n;
205 	else if(p==p1)
206 		inslist(r, i, n);
207 	else{			/* must break piece in terminal */
208 		inslist(r, i+1, (L(i)-(p1-p))|M);
209 		inslist(r, i+1, n);
210 		P(i) = (p1-p)|M;
211 	}
212 }
213 
214 int
215 rterm(List *r, Posn p1)
216 {
217 	Posn p;
218 	int i;
219 
220 	for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
221 		;
222 	if(i==r->nused && (i==0 || !T(i-1)))
223 		return 0;
224 	return T(i);
225 }
226 
227 Range
228 rdata(List *r, Posn p1, Posn n)
229 {
230 	Posn p;
231 	int i;
232 	Range rg;
233 
234 	if(n==0)
235 		panic("rdata 0");
236 	for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
237 		;
238 	if(i==r->nused)
239 		panic("rdata 1");
240 	if(T(i)){
241 		n-=L(i)-(p1-p);
242 		if(n<=0){
243 			rg.p1 = rg.p2 = p1;
244 			return rg;
245 		}
246 		p+=L(i++);
247 		p1 = p;
248 	}
249 	if(T(i) || i==r->nused)
250 		panic("rdata 2");
251 	if(p+L(i)<p1+n)
252 		n = L(i)-(p1-p);
253 	rg.p1 = p1;
254 	rg.p2 = p1+n;
255 	if(p!=p1){
256 		inslist(r, i+1, L(i)-(p1-p));
257 		P(i)=p1-p;
258 		i++;
259 	}
260 	if(L(i)!=n){
261 		inslist(r, i+1, L(i)-n);
262 		P(i)=n;
263 	}
264 	P(i)|=M;
265 	/* now i is set; can we merge? */
266 	if(i<r->nused-1 && T(i+1)){
267 		P(i)=(n+=L(i+1))|M;
268 		dellist(r, i+1);
269 	}
270 	if(i>0 && T(i-1)){
271 		P(i)=(n+L(i-1))|M;
272 		dellist(r, i-1);
273 	}
274 	return rg;
275 }
276