xref: /plan9-contrib/sys/src/cmd/sam/address.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include "sam.h"
2 #include "parse.h"
3 
4 Address	addr;
5 String	lastpat;
6 int	patset;
7 File	*menu;
8 
9 File	*matchfile(String*);
10 Address	charaddr(Posn, Address, int);
11 
12 Address
address(Addr * ap,Address a,int sign)13 address(Addr *ap, Address a, int sign)
14 {
15 	File *f = a.f;
16 	Address a1, a2;
17 
18 	do{
19 		switch(ap->type){
20 		case 'l':
21 		case '#':
22 			a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign);
23 			break;
24 
25 		case '.':
26 			a = f->dot;
27 			break;
28 
29 		case '$':
30 			a.r.p1 = a.r.p2 = f->nc;
31 			break;
32 
33 		case '\'':
34 			a.r = f->mark;
35 			break;
36 
37 		case '?':
38 			sign = -sign;
39 			if(sign == 0)
40 				sign = -1;
41 			/* fall through */
42 		case '/':
43 			nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign);
44 			a.r = sel.p[0];
45 			break;
46 
47 		case '"':
48 			a = matchfile(ap->are)->dot;
49 			f = a.f;
50 			if(f->unread)
51 				load(f);
52 			break;
53 
54 		case '*':
55 			a.r.p1 = 0, a.r.p2 = f->nc;
56 			return a;
57 
58 		case ',':
59 		case ';':
60 			if(ap->left)
61 				a1 = address(ap->left, a, 0);
62 			else
63 				a1.f = a.f, a1.r.p1 = a1.r.p2 = 0;
64 			if(ap->type == ';'){
65 				f = a1.f;
66 				a = a1;
67 				f->dot = a1;
68 			}
69 			if(ap->next)
70 				a2 = address(ap->next, a, 0);
71 			else
72 				a2.f = a.f, a2.r.p1 = a2.r.p2 = f->nc;
73 			if(a1.f != a2.f)
74 				error(Eorder);
75 			a.f = a1.f, a.r.p1 = a1.r.p1, a.r.p2 = a2.r.p2;
76 			if(a.r.p2 < a.r.p1)
77 				error(Eorder);
78 			return a;
79 
80 		case '+':
81 		case '-':
82 			sign = 1;
83 			if(ap->type == '-')
84 				sign = -1;
85 			if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-')
86 				a = lineaddr(1L, a, sign);
87 			break;
88 		default:
89 			panic("address");
90 			return a;
91 		}
92 	}while(ap = ap->next);	/* assign = */
93 	return a;
94 }
95 
96 void
nextmatch(File * f,String * r,Posn p,int sign)97 nextmatch(File *f, String *r, Posn p, int sign)
98 {
99 	compile(r);
100 	if(sign >= 0){
101 		if(!execute(f, p, INFINITY))
102 			error(Esearch);
103 		if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p1==p){
104 			if(++p>f->nc)
105 				p = 0;
106 			if(!execute(f, p, INFINITY))
107 				panic("address");
108 		}
109 	}else{
110 		if(!bexecute(f, p))
111 			error(Esearch);
112 		if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p2==p){
113 			if(--p<0)
114 				p = f->nc;
115 			if(!bexecute(f, p))
116 				panic("address");
117 		}
118 	}
119 }
120 
121 File *
matchfile(String * r)122 matchfile(String *r)
123 {
124 	File *f;
125 	File *match = 0;
126 	int i;
127 
128 	for(i = 0; i<file.nused; i++){
129 		f = file.filepptr[i];
130 		if(f == cmd)
131 			continue;
132 		if(filematch(f, r)){
133 			if(match)
134 				error(Emanyfiles);
135 			match = f;
136 		}
137 	}
138 	if(!match)
139 		error(Efsearch);
140 	return match;
141 }
142 
143 int
filematch(File * f,String * r)144 filematch(File *f, String *r)
145 {
146 	char *c, buf[STRSIZE+100];
147 	String *t;
148 
149 	c = Strtoc(&f->name);
150 	sprint(buf, "%c%c%c %s\n", " '"[f->mod],
151 		"-+"[f->rasp!=0], " ."[f==curfile], c);
152 	free(c);
153 	t = tmpcstr(buf);
154 	Strduplstr(&genstr, t);
155 	freetmpstr(t);
156 	/* A little dirty... */
157 	if(menu == 0)
158 		menu = fileopen();
159 	bufreset(menu);
160 	bufinsert(menu, 0, genstr.s, genstr.n);
161 	compile(r);
162 	return execute(menu, 0, menu->nc);
163 }
164 
165 Address
charaddr(Posn l,Address addr,int sign)166 charaddr(Posn l, Address addr, int sign)
167 {
168 	if(sign == 0)
169 		addr.r.p1 = addr.r.p2 = l;
170 	else if(sign < 0)
171 		addr.r.p2 = addr.r.p1-=l;
172 	else if(sign > 0)
173 		addr.r.p1 = addr.r.p2+=l;
174 	if(addr.r.p1<0 || addr.r.p2>addr.f->nc)
175 		error(Erange);
176 	return addr;
177 }
178 
179 Address
lineaddr(Posn l,Address addr,int sign)180 lineaddr(Posn l, Address addr, int sign)
181 {
182 	int n;
183 	int c;
184 	File *f = addr.f;
185 	Address a;
186 	Posn p;
187 
188 	a.f = f;
189 	if(sign >= 0){
190 		if(l == 0){
191 			if(sign==0 || addr.r.p2==0){
192 				a.r.p1 = a.r.p2 = 0;
193 				return a;
194 			}
195 			a.r.p1 = addr.r.p2;
196 			p = addr.r.p2-1;
197 		}else{
198 			if(sign==0 || addr.r.p2==0){
199 				p = (Posn)0;
200 				n = 1;
201 			}else{
202 				p = addr.r.p2-1;
203 				n = filereadc(f, p++)=='\n';
204 			}
205 			while(n < l){
206 				if(p >= f->nc)
207 					error(Erange);
208 				if(filereadc(f, p++) == '\n')
209 					n++;
210 			}
211 			a.r.p1 = p;
212 		}
213 		while(p < f->nc && filereadc(f, p++)!='\n')
214 			;
215 		a.r.p2 = p;
216 	}else{
217 		p = addr.r.p1;
218 		if(l == 0)
219 			a.r.p2 = addr.r.p1;
220 		else{
221 			for(n = 0; n<l; ){	/* always runs once */
222 				if(p == 0){
223 					if(++n != l)
224 						error(Erange);
225 				}else{
226 					c = filereadc(f, p-1);
227 					if(c != '\n' || ++n != l)
228 						p--;
229 				}
230 			}
231 			a.r.p2 = p;
232 			if(p > 0)
233 				p--;
234 		}
235 		while(p > 0 && filereadc(f, p-1)!='\n')	/* lines start after a newline */
236 			p--;
237 		a.r.p1 = p;
238 	}
239 	return a;
240 }
241