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 "dat.h"
12 #include "fns.h"
14 enum
15 {
16 None = 0,
17 Fore = '+',
18 Back = '-',
19 };
21 enum
22 {
23 Char,
24 Line,
25 };
27 int
28 isaddrc(int r)
29 {
30 if(r && utfrune("0123456789+-/$.#,;", r)!=nil)
31 return TRUE;
32 return FALSE;
33 }
35 /*
36 * quite hard: could be almost anything but white space, but we are a little conservative,
37 * aiming for regular expressions of alphanumerics and no white space
38 */
39 int
40 isregexc(int r)
41 {
42 if(r == 0)
43 return FALSE;
44 if(isalnum(r))
45 return TRUE;
46 if(utfrune("^+-.*?#,;[]()$", r)!=nil)
47 return TRUE;
48 return FALSE;
49 }
51 Range
52 number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
53 {
54 uint q0, q1;
56 if(size == Char){
57 if(dir == Fore)
58 line = r.q1+line;
59 else if(dir == Back){
60 if(r.q0==0 && line>0)
61 r.q0 = t->file->b.nc;
62 line = r.q0 - line;
63 }
64 if(line<0 || line>t->file->b.nc)
65 goto Rescue;
66 *evalp = TRUE;
67 return range(line, line);
68 }
69 q0 = r.q0;
70 q1 = r.q1;
71 switch(dir){
72 case None:
73 q0 = 0;
74 q1 = 0;
75 Forward:
76 while(line>0 && q1<t->file->b.nc)
77 if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc)
78 if(--line > 0)
79 q0 = q1;
80 if(line > 0)
81 goto Rescue;
82 break;
83 case Fore:
84 if(q1 > 0)
85 while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
86 q1++;
87 q0 = q1;
88 goto Forward;
89 case Back:
90 if(q0 < t->file->b.nc)
91 while(q0>0 && textreadc(t, q0-1)!='\n')
92 q0--;
93 q1 = q0;
94 while(line>0 && q0>0){
95 if(textreadc(t, q0-1) == '\n'){
96 if(--line >= 0)
97 q1 = q0;
98 }
99 --q0;
101 if(line > 0)
102 goto Rescue;
103 while(q0>0 && textreadc(t, q0-1)!='\n')
104 --q0;
106 *evalp = TRUE;
107 return range(q0, q1);
109 Rescue:
110 if(showerr)
111 warning(nil, "address out of range\n");
112 *evalp = FALSE;
113 return r;
117 Range
118 regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
120 int found;
121 Rangeset sel;
122 int q;
124 if(pat[0] == '\0' && rxnull()){
125 if(showerr)
126 warning(nil, "no previous regular expression\n");
127 *foundp = FALSE;
128 return r;
130 if(pat[0] && rxcompile(pat) == FALSE){
131 *foundp = FALSE;
132 return r;
134 if(dir == Back)
135 found = rxbexecute(t, r.q0, &sel);
136 else{
137 if(lim.q0 < 0)
138 q = Infinity;
139 else
140 q = lim.q1;
141 found = rxexecute(t, nil, r.q1, q, &sel);
143 if(!found && showerr)
144 warning(nil, "no match for regexp\n");
145 *foundp = found;
146 return sel.r[0];
149 Range
150 address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
152 int dir, size, npat;
153 int prevc, c, nc, n;
154 uint q;
155 Rune *pat;
156 Range r, nr;
158 r = ar;
159 q = q0;
160 dir = None;
161 size = Line;
162 c = 0;
163 while(q < q1){
164 prevc = c;
165 c = (*getc)(a, q++);
166 switch(c){
167 default:
168 *qp = q-1;
169 return r;
170 case ';':
171 ar = r;
172 /* fall through */
173 case ',':
174 if(prevc == 0) /* lhs defaults to 0 */
175 r.q0 = 0;
176 if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
177 r.q1 = t->file->b.nc;
178 else{
179 nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
180 r.q1 = nr.q1;
182 *qp = q;
183 return r;
184 case '+':
185 case '-':
186 if(*evalp && (prevc=='+' || prevc=='-'))
187 if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
188 r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
189 dir = c;
190 break;
191 case '.':
192 case '$':
193 if(q != q0+1){
194 *qp = q-1;
195 return r;
197 if(*evalp)
198 if(c == '.')
199 r = ar;
200 else
201 r = range(t->file->b.nc, t->file->b.nc);
202 if(q < q1)
203 dir = Fore;
204 else
205 dir = None;
206 break;
207 case '#':
208 if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
209 *qp = q-1;
210 return r;
212 size = Char;
213 /* fall through */
214 case '0': case '1': case '2': case '3': case '4':
215 case '5': case '6': case '7': case '8': case '9':
216 n = c -'0';
217 while(q<q1){
218 c = (*getc)(a, q++);
219 if(c<'0' || '9'<c){
220 q--;
221 break;
223 n = n*10+(c-'0');
225 if(*evalp)
226 r = number(showerr, t, r, n, dir, size, evalp);
227 dir = None;
228 size = Line;
229 break;
230 case '?':
231 dir = Back;
232 /* fall through */
233 case '/':
234 npat = 0;
235 pat = nil;
236 while(q<q1){
237 c = (*getc)(a, q++);
238 switch(c){
239 case '\n':
240 --q;
241 goto out;
242 case '\\':
243 pat = runerealloc(pat, npat+1);
244 pat[npat++] = c;
245 if(q == q1)
246 goto out;
247 c = (*getc)(a, q++);
248 break;
249 case '/':
250 goto out;
252 pat = runerealloc(pat, npat+1);
253 pat[npat++] = c;
255 out:
256 pat = runerealloc(pat, npat+1);
257 pat[npat] = 0;
258 if(*evalp)
259 r = regexp(showerr, t, lim, r, pat, dir, evalp);
260 free(pat);
261 dir = None;
262 size = Line;
263 break;
266 if(*evalp && dir != None)
267 r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
268 *qp = q;
269 return r;