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" 13 14 enum 15 { 16 None = 0, 17 Fore = '+', 18 Back = '-', 19 }; 20 21 enum 22 { 23 Char, 24 Line, 25 }; 26 27 int 28 isaddrc(int r) 29 { 30 if(r && utfrune("0123456789+-/$.#,;", r)!=nil) 31 return TRUE; 32 return FALSE; 33 } 34 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 } 50 51 Range 52 number(Mntdir *md, Text *t, Range r, int line, int dir, int size, int *evalp) 53 { 54 uint q0, q1; 55 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->nc; 62 line = r.q0 - line; 63 } 64 if(line<0 || line>t->file->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->nc) 77 if(textreadc(t, q1++) == '\n' || q1==t->file->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->nc && textreadc(t, q1-1) != '\n') 86 q1++; 87 q0 = q1; 88 goto Forward; 89 case Back: 90 if(q0 < t->file->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; 100 } 101 if(line > 0) 102 goto Rescue; 103 while(q0>0 && textreadc(t, q0-1)!='\n') 104 --q0; 105 } 106 *evalp = TRUE; 107 return (Range){q0, q1}; 108 109 Rescue: 110 if(md != nil) 111 warning(nil, "address out of range\n"); 112 *evalp = FALSE; 113 return r; 114 } 115 116 117 Range 118 regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp) 119 { 120 int found; 121 Rangeset sel; 122 int q; 123 124 if(pat[0] == '\0' && rxnull()){ 125 warning(md, "no previous regular expression\n"); 126 *foundp = FALSE; 127 return r; 128 } 129 if(pat[0] && rxcompile(pat) == FALSE){ 130 *foundp = FALSE; 131 return r; 132 } 133 if(dir == Back) 134 found = rxbexecute(t, r.q0, &sel); 135 else{ 136 if(lim.q0 < 0) 137 q = Infinity; 138 else 139 q = lim.q1; 140 found = rxexecute(t, nil, r.q1, q, &sel); 141 } 142 if(!found && md==nil) 143 warning(nil, "no match for regexp\n"); 144 *foundp = found; 145 return sel.r[0]; 146 } 147 148 Range 149 address(Mntdir *md, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp) 150 { 151 int dir, size, npat; 152 int prevc, c, nc, n; 153 uint q; 154 Rune *pat; 155 Range r, nr; 156 157 r = ar; 158 q = q0; 159 dir = None; 160 size = Line; 161 c = 0; 162 while(q < q1){ 163 prevc = c; 164 c = (*getc)(a, q++); 165 switch(c){ 166 default: 167 *qp = q-1; 168 return r; 169 case ';': 170 ar = r; 171 /* fall through */ 172 case ',': 173 if(prevc == 0) /* lhs defaults to 0 */ 174 r.q0 = 0; 175 if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */ 176 r.q1 = t->file->nc; 177 else{ 178 nr = address(md, t, lim, ar, a, q, q1, getc, evalp, &q); 179 r.q1 = nr.q1; 180 } 181 *qp = q; 182 return r; 183 case '+': 184 case '-': 185 if(*evalp && (prevc=='+' || prevc=='-')) 186 if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?') 187 r = number(md, t, r, 1, prevc, Line, evalp); /* do previous one */ 188 dir = c; 189 break; 190 case '.': 191 case '$': 192 if(q != q0+1){ 193 *qp = q-1; 194 return r; 195 } 196 if(*evalp) 197 if(c == '.') 198 r = ar; 199 else 200 r = (Range){t->file->nc, t->file->nc}; 201 if(q < q1) 202 dir = Fore; 203 else 204 dir = None; 205 break; 206 case '#': 207 if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){ 208 *qp = q-1; 209 return r; 210 } 211 size = Char; 212 /* fall through */ 213 case '0': case '1': case '2': case '3': case '4': 214 case '5': case '6': case '7': case '8': case '9': 215 n = c -'0'; 216 while(q<q1){ 217 c = (*getc)(a, q++); 218 if(c<'0' || '9'<c){ 219 q--; 220 break; 221 } 222 n = n*10+(c-'0'); 223 } 224 if(*evalp) 225 r = number(md, t, r, n, dir, size, evalp); 226 dir = None; 227 size = Line; 228 break; 229 case '?': 230 dir = Back; 231 /* fall through */ 232 case '/': 233 npat = 0; 234 pat = nil; 235 while(q<q1){ 236 c = (*getc)(a, q++); 237 switch(c){ 238 case '\n': 239 --q; 240 goto out; 241 case '\\': 242 pat = runerealloc(pat, npat+1); 243 pat[npat++] = c; 244 if(q == q1) 245 goto out; 246 c = (*getc)(a, q++); 247 break; 248 case '/': 249 goto out; 250 } 251 pat = runerealloc(pat, npat+1); 252 pat[npat++] = c; 253 } 254 out: 255 pat = runerealloc(pat, npat+1); 256 pat[npat] = 0; 257 if(*evalp) 258 r = regexp(md, t, lim, r, pat, dir, evalp); 259 free(pat); 260 dir = None; 261 size = Line; 262 break; 263 } 264 } 265 if(*evalp && dir != None) 266 r = number(md, t, r, 1, dir, Line, evalp); /* do previous one */ 267 *qp = q; 268 return r; 269 } 270