Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <fcall.h>
10 #include <plumb.h>
11 #include <libsec.h>
12 #include "dat.h"
13 #include "fns.h"
15 enum
16 {
17 None = 0,
18 Fore = '+',
19 Back = '-'
20 };
22 enum
23 {
24 Char,
25 Line
26 };
28 int
29 isaddrc(int r)
30 {
31 if(r && utfrune("0123456789+-/$.#,;?", r)!=nil)
32 return TRUE;
33 return FALSE;
34 }
36 /*
37 * quite hard: could be almost anything but white space, but we are a little conservative,
38 * aiming for regular expressions of alphanumerics and no white space
39 */
40 int
41 isregexc(int r)
42 {
43 if(r == 0)
44 return FALSE;
45 if(isalnum(r))
46 return TRUE;
47 if(utfrune("^+-.*?#,;[]()$", r)!=nil)
48 return TRUE;
49 return FALSE;
50 }
52 // nlcounttopos starts at q0 and advances nl lines,
53 // being careful not to walk past the end of the text,
54 // and then nr chars, being careful not to walk past
55 // the end of the current line.
56 // It returns the final position.
57 long
58 nlcounttopos(Text *t, long q0, long nl, long nr)
59 {
60 while(nl > 0 && q0 < t->file->b.nc) {
61 if(textreadc(t, q0++) == '\n')
62 nl--;
63 }
64 if(nl > 0)
65 return q0;
66 while(nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
67 q0++;
68 nr--;
69 }
70 return q0;
71 }
73 Range
74 number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
75 {
76 uint q0, q1;
78 if(size == Char){
79 if(dir == Fore)
80 line = r.q1+line;
81 else if(dir == Back){
82 if(r.q0==0 && line>0)
83 r.q0 = t->file->b.nc;
84 line = r.q0 - line;
85 }
86 if(line<0 || line>t->file->b.nc)
87 goto Rescue;
88 *evalp = TRUE;
89 return range(line, line);
90 }
91 q0 = r.q0;
92 q1 = r.q1;
93 switch(dir){
94 case None:
95 q0 = 0;
96 q1 = 0;
97 Forward:
98 while(line>0 && q1<t->file->b.nc)
99 if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc)
100 if(--line > 0)
101 q0 = q1;
102 if(line==1 && q1==t->file->b.nc) // 6 goes to end of 5-line file
103 break;
104 if(line > 0)
105 goto Rescue;
106 break;
107 case Fore:
108 if(q1 > 0)
109 while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
110 q1++;
111 q0 = q1;
112 goto Forward;
113 case Back:
114 if(q0 < t->file->b.nc)
115 while(q0>0 && textreadc(t, q0-1)!='\n')
116 q0--;
117 q1 = q0;
118 while(line>0 && q0>0){
119 if(textreadc(t, q0-1) == '\n'){
120 if(--line >= 0)
121 q1 = q0;
123 --q0;
125 /* :1-1 is :0 = #0, but :1-2 is an error */
126 if(line > 1)
127 goto Rescue;
128 while(q0>0 && textreadc(t, q0-1)!='\n')
129 --q0;
131 *evalp = TRUE;
132 return range(q0, q1);
134 Rescue:
135 if(showerr)
136 warning(nil, "address out of range\n");
137 *evalp = FALSE;
138 return r;
142 Range
143 regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
145 int found;
146 Rangeset sel;
147 int q;
149 if(pat[0] == '\0' && rxnull()){
150 if(showerr)
151 warning(nil, "no previous regular expression\n");
152 *foundp = FALSE;
153 return r;
155 if(pat[0] && rxcompile(pat) == FALSE){
156 *foundp = FALSE;
157 return r;
159 if(dir == Back)
160 found = rxbexecute(t, r.q0, &sel);
161 else{
162 if(lim.q0 < 0)
163 q = Infinity;
164 else
165 q = lim.q1;
166 found = rxexecute(t, nil, r.q1, q, &sel);
168 if(!found && showerr)
169 warning(nil, "no match for regexp\n");
170 *foundp = found;
171 return sel.r[0];
174 Range
175 address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
177 int dir, size, npat;
178 int prevc, c, nc, n;
179 uint q;
180 Rune *pat;
181 Range r, nr;
183 r = ar;
184 q = q0;
185 dir = None;
186 size = Line;
187 c = 0;
188 while(q < q1){
189 prevc = c;
190 c = (*getc)(a, q++);
191 switch(c){
192 default:
193 *qp = q-1;
194 return r;
195 case ';':
196 ar = r;
197 /* fall through */
198 case ',':
199 if(prevc == 0) /* lhs defaults to 0 */
200 r.q0 = 0;
201 if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
202 r.q1 = t->file->b.nc;
203 else{
204 nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
205 r.q1 = nr.q1;
207 *qp = q;
208 return r;
209 case '+':
210 case '-':
211 if(*evalp && (prevc=='+' || prevc=='-'))
212 if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
213 r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
214 dir = c;
215 break;
216 case '.':
217 case '$':
218 if(q != q0+1){
219 *qp = q-1;
220 return r;
222 if(*evalp)
223 if(c == '.')
224 r = ar;
225 else
226 r = range(t->file->b.nc, t->file->b.nc);
227 if(q < q1)
228 dir = Fore;
229 else
230 dir = None;
231 break;
232 case '#':
233 if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
234 *qp = q-1;
235 return r;
237 size = Char;
238 /* fall through */
239 case '0': case '1': case '2': case '3': case '4':
240 case '5': case '6': case '7': case '8': case '9':
241 n = c -'0';
242 while(q<q1){
243 nc = (*getc)(a, q++);
244 if(nc<'0' || '9'<nc){
245 q--;
246 break;
248 n = n*10+(nc-'0');
250 if(*evalp)
251 r = number(showerr, t, r, n, dir, size, evalp);
252 dir = None;
253 size = Line;
254 break;
255 case '?':
256 dir = Back;
257 /* fall through */
258 case '/':
259 npat = 0;
260 pat = nil;
261 while(q<q1){
262 c = (*getc)(a, q++);
263 switch(c){
264 case '\n':
265 --q;
266 goto out;
267 case '\\':
268 pat = runerealloc(pat, npat+1);
269 pat[npat++] = c;
270 if(q == q1)
271 goto out;
272 c = (*getc)(a, q++);
273 break;
274 case '/':
275 goto out;
277 pat = runerealloc(pat, npat+1);
278 pat[npat++] = c;
280 out:
281 pat = runerealloc(pat, npat+1);
282 pat[npat] = 0;
283 if(*evalp)
284 r = regexp(showerr, t, lim, r, pat, dir, evalp);
285 free(pat);
286 dir = None;
287 size = Line;
288 break;
291 if(*evalp && dir != None)
292 r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
293 *qp = q;
294 return r;