]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/sam/address.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / sam / address.c
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
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
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 *
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
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
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
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 }