Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
static	Posn	growpos;
13
static	Posn	grown;
14
static	Posn	shrinkpos;
15
static	Posn	shrunk;
16
 
17
/*
18
 * rasp routines inform the terminal of changes to the file.
19
 *
20
 * a rasp is a list of spans within the file, and an indication
21
 * of whether the terminal knows about the span.
22
 *
23
 * optimize by coalescing multiple updates to the same span
24
 * if it is not known by the terminal.
25
 *
26
 * other possible optimizations: flush terminal's rasp by cut everything,
27
 * insert everything if rasp gets too large.
28
 */
29
 
30
/*
31
 * only called for initial load of file
32
 */
33
void
34
raspload(File *f)
35
{
36
	if(f->rasp == nil)
37
		return;
38
	grown = f->nc;
39
	growpos = 0;
40
	if(f->nc)
41
		rgrow(f->rasp, 0, f->nc);
42
	raspdone(f, 1);
43
}
44
 
45
void
46
raspstart(File *f)
47
{
48
	if(f->rasp == nil)
49
		return;
50
	grown = 0;
51
	shrunk = 0;
52
	outbuffered = 1;
53
}
54
 
55
void
56
raspdone(File *f, int toterm)
57
{
58
	if(f->dot.r.p1 > f->nc)
59
		f->dot.r.p1 = f->nc;
60
	if(f->dot.r.p2 > f->nc)
61
		f->dot.r.p2 = f->nc;
62
	if(f->mark.p1 > f->nc)
63
		f->mark.p1 = f->nc;
64
	if(f->mark.p2 > f->nc)
65
		f->mark.p2 = f->nc;
66
	if(f->rasp == nil)
67
		return;
68
	if(grown)
69
		outTsll(Hgrow, f->tag, growpos, grown);
70
	else if(shrunk)
71
		outTsll(Hcut, f->tag, shrinkpos, shrunk);
72
	if(toterm)
73
		outTs(Hcheck0, f->tag);
74
	outflush();
75
	outbuffered = 0;
76
	if(f == cmd){
77
		cmdpt += cmdptadv;
78
		cmdptadv = 0;
79
	}
80
}
81
 
82
void
83
raspflush(File *f)
84
{
85
	if(grown){
86
		outTsll(Hgrow, f->tag, growpos, grown);
87
		grown = 0;
88
	}
89
	else if(shrunk){
90
		outTsll(Hcut, f->tag, shrinkpos, shrunk);
91
		shrunk = 0;
92
	}
93
	outflush();
94
}
95
 
96
void
97
raspdelete(File *f, uint p1, uint p2, int toterm)
98
{
99
	long n;
100
 
101
	n = p2 - p1;
102
	if(n == 0)
103
		return;
104
 
105
	if(p2 <= f->dot.r.p1){
106
		f->dot.r.p1 -= n;
107
		f->dot.r.p2 -= n;
108
	}
109
	if(p2 <= f->mark.p1){
110
		f->mark.p1 -= n;
111
		f->mark.p2 -= n;
112
	}
113
 
114
	if(f->rasp == nil)
115
		return;
116
 
117
	if(f==cmd && p1<cmdpt){
118
		if(p2 <= cmdpt)
119
			cmdpt -= n;
120
		else
121
			cmdpt = p1;
122
	}
123
	if(toterm){
124
		if(grown){
125
			outTsll(Hgrow, f->tag, growpos, grown);
126
			grown = 0;
127
		}else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){
128
			outTsll(Hcut, f->tag, shrinkpos, shrunk);
129
			shrunk = 0;
130
		}
131
		if(!shrunk || shrinkpos==p2)
132
			shrinkpos = p1;
133
		shrunk += n;
134
	}
135
	rcut(f->rasp, p1, p2);
136
}
137
 
138
void
139
raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm)
140
{
141
	Range r;
142
 
143
	if(n == 0)
144
		return;
145
 
146
	if(p1 < f->dot.r.p1){
147
		f->dot.r.p1 += n;
148
		f->dot.r.p2 += n;
149
	}
150
	if(p1 < f->mark.p1){
151
		f->mark.p1 += n;
152
		f->mark.p2 += n;
153
	}
154
 
155
 
156
	if(f->rasp == nil)
157
		return;
158
	if(f==cmd && p1<cmdpt)
159
		cmdpt += n;
160
	if(toterm){
161
		if(shrunk){
162
			outTsll(Hcut, f->tag, shrinkpos, shrunk);
163
			shrunk = 0;
164
		}
165
		if(n>GROWDATASIZE || !rterm(f->rasp, p1)){
166
			rgrow(f->rasp, p1, n);
167
			if(grown && growpos+grown!=p1 && growpos!=p1){
168
				outTsll(Hgrow, f->tag, growpos, grown);
169
				grown = 0;
170
			}
171
			if(!grown)
172
				growpos = p1;
173
			grown += n;
174
		}else{
175
			if(grown){
176
				outTsll(Hgrow, f->tag, growpos, grown);
177
				grown = 0;
178
			}
179
			rgrow(f->rasp, p1, n);
180
			r = rdata(f->rasp, p1, n);
181
			if(r.p1!=p1 || r.p2!=p1+n)
182
				panic("rdata in toterminal");
183
			outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n));
184
		}
185
	}else{
186
		rgrow(f->rasp, p1, n);
187
		r = rdata(f->rasp, p1, n);
188
		if(r.p1!=p1 || r.p2!=p1+n)
189
			panic("rdata in toterminal");
190
	}
191
}
192
 
193
#define	M	0x80000000L
194
#define	P(i)	r->posnptr[i]
195
#define	T(i)	(P(i)&M)	/* in terminal */
196
#define	L(i)	(P(i)&~M)	/* length of this piece */
197
 
198
void
199
rcut(List *r, Posn p1, Posn p2)
200
{
201
	Posn p, x;
202
	int i;
203
 
204
	if(p1 == p2)
205
		panic("rcut 0");
206
	for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
207
		;
208
	if(i == r->nused)
209
		panic("rcut 1");
210
	if(p < p1){	/* chop this piece */
211
		if(p+L(i) < p2){
212
			x = p1-p;
213
			p += L(i);
214
		}else{
215
			x = L(i)-(p2-p1);
216
			p = p2;
217
		}
218
		if(T(i))
219
			P(i) = x|M;
220
		else
221
			P(i) = x;
222
		i++;
223
	}
224
	while(i<r->nused && p+L(i)<=p2){
225
		p += L(i);
226
		dellist(r, i);
227
	}
228
	if(p < p2){
229
		if(i == r->nused)
230
			panic("rcut 2");
231
		x = L(i)-(p2-p);
232
		if(T(i))
233
			P(i) = x|M;
234
		else
235
			P(i) = x;
236
	}
237
	/* can we merge i and i-1 ? */
238
	if(i>0 && i<r->nused && T(i-1)==T(i)){
239
		x = L(i-1)+L(i);
240
		dellist(r, i--);
241
		if(T(i))
242
			P(i)=x|M;
243
		else
244
			P(i)=x;
245
	}
246
}
247
 
248
void
249
rgrow(List *r, Posn p1, Posn n)
250
{
251
	Posn p;
252
	int i;
253
 
254
	if(n == 0)
255
		panic("rgrow 0");
256
	for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
257
		;
258
	if(i == r->nused){	/* stick on end of file */
259
		if(p!=p1)
260
			panic("rgrow 1");
261
		if(i>0 && !T(i-1))
262
			P(i-1)+=n;
263
		else
264
			inslist(r, i, n);
265
	}else if(!T(i))		/* goes in this empty piece */
266
		P(i)+=n;
267
	else if(p==p1 && i>0 && !T(i-1))	/* special case; simplifies life */
268
		P(i-1)+=n;
269
	else if(p==p1)
270
		inslist(r, i, n);
271
	else{			/* must break piece in terminal */
272
		inslist(r, i+1, (L(i)-(p1-p))|M);
273
		inslist(r, i+1, n);
274
		P(i) = (p1-p)|M;
275
	}
276
}
277
 
278
int
279
rterm(List *r, Posn p1)
280
{
281
	Posn p;
282
	int i;
283
 
284
	for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
285
		;
286
	if(i==r->nused && (i==0 || !T(i-1)))
287
		return 0;
288
	return T(i);
289
}
290
 
291
Range
292
rdata(List *r, Posn p1, Posn n)
293
{
294
	Posn p;
295
	int i;
296
	Range rg;
297
 
298
	if(n==0)
299
		panic("rdata 0");
300
	for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
301
		;
302
	if(i==r->nused)
303
		panic("rdata 1");
304
	if(T(i)){
305
		n-=L(i)-(p1-p);
306
		if(n<=0){
307
			rg.p1 = rg.p2 = p1;
308
			return rg;
309
		}
310
		p+=L(i++);
311
		p1 = p;
312
	}
313
	if(T(i) || i==r->nused)
314
		panic("rdata 2");
315
	if(p+L(i)<p1+n)
316
		n = L(i)-(p1-p);
317
	rg.p1 = p1;
318
	rg.p2 = p1+n;
319
	if(p!=p1){
320
		inslist(r, i+1, L(i)-(p1-p));
321
		P(i)=p1-p;
322
		i++;
323
	}
324
	if(L(i)!=n){
325
		inslist(r, i+1, L(i)-n);
326
		P(i)=n;
327
	}
328
	P(i)|=M;
329
	/* now i is set; can we merge? */
330
	if(i<r->nused-1 && T(i+1)){
331
		P(i)=(n+=L(i+1))|M;
332
		dellist(r, i+1);
333
	}
334
	if(i>0 && T(i-1)){
335
		P(i)=(n+L(i-1))|M;
336
		dellist(r, i-1);
337
	}
338
	return rg;
339
}