xref: /plan9-contrib/sys/src/cmd/samterm/rasp.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <libg.h>
4 #include <frame.h>
5 #include "flayer.h"
6 #include "samterm.h"
7 
8 void
9 rinit(Rasp *r)
10 {
11 	r->nrunes=0;
12 	r->sect=0;
13 }
14 
15 void
16 rclear(Rasp *r)
17 {
18 	Section *s, *ns;
19 
20 	for(s=r->sect; s; s=ns){
21 		ns = s->next;
22 		free(s->text);
23 		free(s);
24 	}
25 	r->sect = 0;
26 }
27 
28 Section*
29 rsinsert(Rasp *r, Section *s)	/* insert before s */
30 {
31 	Section *t;
32 	Section *u;
33 
34 	t = alloc(sizeof(Section));
35 	if(r->sect == s){	/* includes empty list case: r->sect==s==0 */
36 		r->sect = t;
37 		t->next = s;
38 	}else{
39 		u = r->sect;
40 		if(u == 0)
41 			panic("rsinsert 1");
42 		do{
43 			if(u->next == s){
44 				t->next = s;
45 				u->next = t;
46 				goto Return;
47 			}
48 			u=u->next;
49 		}while(u);
50 		panic("rsinsert 2");
51 	}
52     Return:
53 	return t;
54 }
55 
56 void
57 rsdelete(Rasp *r, Section *s)
58 {
59 	Section *t;
60 
61 	if(s == 0)
62 		panic("rsdelete");
63 	if(r->sect == s){
64 		r->sect = s->next;
65 		goto Free;
66 	}
67 	for(t=r->sect; t; t=t->next)
68 		if(t->next == s){
69 			t->next = s->next;
70 	Free:
71 			if(s->text)
72 				free(s->text);
73 			free(s);
74 			return;
75 		}
76 	panic("rsdelete 2");
77 }
78 
79 void
80 splitsect(Rasp *r, Section *s, long n0)
81 {
82 	if(s == 0)
83 		panic("splitsect");
84 	rsinsert(r, s->next);
85 	if(s->text == 0)
86 		s->next->text = 0;
87 	else{
88 		s->next->text = alloc(RUNESIZE*(TBLOCKSIZE+1));
89 		Strcpy(s->next->text, s->text+n0);
90 		s->text[n0] = 0;
91 	}
92 	s->next->nrunes = s->nrunes-n0;
93 	s->nrunes = n0;
94 }
95 
96 Section *
97 findsect(Rasp *r, Section *s, long p, long q)	/* find sect containing q and put q on a sect boundary */
98 {
99 	if(s==0 && p!=q)
100 		panic("findsect");
101 	for(; s && p+s->nrunes<=q; s=s->next)
102 		p += s->nrunes;
103 	if(p != q){
104 		splitsect(r, s, q-p);
105 		s = s->next;
106 	}
107 	return s;
108 }
109 
110 void
111 rresize(Rasp *r, long a, long old, long new)
112 {
113 	Section *s, *t, *ns;
114 
115 	s = findsect(r, r->sect, 0L, a);
116 	t = findsect(r, s, a, a+old);
117 	for(; s!=t; s=ns){
118 		ns=s->next;
119 		rsdelete(r, s);
120 	}
121 	/* now insert the new piece before t */
122 	if(new > 0){
123 		ns=rsinsert(r, t);
124 		ns->nrunes=new;
125 		ns->text=0;
126 	}
127 	r->nrunes += new-old;
128 }
129 
130 void
131 rdata(Rasp *r, long p0, long p1, Rune *cp)
132 {
133 	Section *s, *t, *ns;
134 
135 	s = findsect(r, r->sect, 0L, p0);
136 	t = findsect(r, s, p0, p1);
137 	for(; s!=t; s=ns){
138 		ns=s->next;
139 		if(s->text)
140 			panic("rdata");
141 		rsdelete(r, s);
142 	}
143 	p1 -= p0;
144 	s = rsinsert(r, t);
145 	s->text = alloc(RUNESIZE*(TBLOCKSIZE+1));
146 	memmove(s->text, cp, RUNESIZE*p1);
147 	s->text[p1] = 0;
148 	s->nrunes = p1;
149 }
150 
151 void
152 rclean(Rasp *r)
153 {
154 	Section *s;
155 
156 	for(s=r->sect; s; s=s->next)
157 		while(s->next && (s->text!=0)==(s->next->text!=0)){
158 			if(s->text){
159 				if(s->nrunes+s->next->nrunes>TBLOCKSIZE)
160 					break;
161 				Strcpy(s->text+s->nrunes, s->next->text);
162 			}
163 			s->nrunes += s->next->nrunes;
164 			rsdelete(r, s->next);
165 		}
166 }
167 
168 void
169 Strcpy(Rune *to, Rune *from)
170 {
171 	do; while(*to++ = *from++);
172 }
173 
174 Rune*
175 rload(Rasp *r, ulong p0, ulong p1, ulong *nrp)
176 {
177 	Section *s;
178 	long p;
179 	int n, nb;
180 
181 	nb = 0;
182 	Strgrow(&scratch, &nscralloc, p1-p0+1);
183 	scratch[0] = 0;
184 	for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next)
185 		p += s->nrunes;
186 	while(p<p1 && s){
187 		/*
188 		 * Subtle and important.  If we are preparing to handle an 'rdata'
189 		 * call, it's because we have an 'rresize' hole here, so the
190 		 * screen doesn't have data for that space anyway (it got cut
191 		 * first).  So pretend it isn't there.
192 		 */
193 		if(s->text){
194 			n = s->nrunes-(p0-p);
195 			if(n>p1-p0)	/* all in this section */
196 				n = p1-p0;
197 			memmove(scratch+nb, s->text+(p0-p), n*RUNESIZE);
198 			nb += n;
199 			scratch[nb] = 0;
200 		}
201 		p += s->nrunes;
202 		p0 = p;
203 		s = s->next;
204 	}
205 	if(nrp)
206 		*nrp = nb;
207 	return scratch;
208 }
209 
210 int
211 rmissing(Rasp *r, ulong p0, ulong p1)
212 {
213 	Section *s;
214 	long p;
215 	int n, nm=0;
216 
217 	for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next)
218 		p += s->nrunes;
219 	while(p<p1 && s){
220 		if(s->text == 0){
221 			n = s->nrunes-(p0-p);
222 			if(n > p1-p0)	/* all in this section */
223 				n = p1-p0;
224 			nm += n;
225 		}
226 		p += s->nrunes;
227 		p0 = p;
228 		s = s->next;
229 	}
230 	return nm;
231 }
232 
233 int
234 rcontig(Rasp *r, ulong p0, ulong p1, int text)
235 {
236 	Section *s;
237 	long p, n;
238 	int np=0;
239 
240 	for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next)
241 		p += s->nrunes;
242 	while(p<p1 && s && (text? (s->text!=0) : (s->text==0))){
243 		n = s->nrunes-(p0-p);
244 		if(n > p1-p0)	/* all in this section */
245 			n = p1-p0;
246 		np += n;
247 		p += s->nrunes;
248 		p0 = p;
249 		s = s->next;
250 	}
251 	return np;
252 }
253 
254 void
255 Strgrow(Rune **s, long *n, int want)	/* can always toss the old data when called */
256 {
257 	if(*n >= want)
258 		return;
259 	free(*s);
260 	*s = alloc(RUNESIZE*want);
261 	*n = want;
262 }
263