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 /* :1-1 is :0 = #0, but :1-2 is an error */ 102 if(line > 1) 103 goto Rescue; 104 while(q0>0 && textreadc(t, q0-1)!='\n') 105 --q0; 106 } 107 *evalp = TRUE; 108 return (Range){q0, q1}; 109 110 Rescue: 111 if(md != nil) 112 warning(nil, "address out of range\n"); 113 *evalp = FALSE; 114 return r; 115 } 116 117 118 Range 119 regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp) 120 { 121 int found; 122 Rangeset sel; 123 int q; 124 125 if(pat[0] == '\0' && rxnull()){ 126 warning(md, "no previous regular expression\n"); 127 *foundp = FALSE; 128 return r; 129 } 130 if(pat[0] && rxcompile(pat) == FALSE){ 131 *foundp = FALSE; 132 return r; 133 } 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); 142 } 143 if(!found && md==nil) 144 warning(nil, "no match for regexp\n"); 145 *foundp = found; 146 return sel.r[0]; 147 } 148 149 Range 150 address(Mntdir *md, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp) 151 { 152 int dir, size, npat; 153 int prevc, c, nc, n; 154 uint q; 155 Rune *pat; 156 Range r, nr; 157 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->nc; 178 else{ 179 nr = address(md, t, lim, ar, a, q, q1, getc, evalp, &q); 180 r.q1 = nr.q1; 181 } 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(md, 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; 196 } 197 if(*evalp) 198 if(c == '.') 199 r = ar; 200 else 201 r = (Range){t->file->nc, t->file->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; 211 } 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; 222 } 223 n = n*10+(c-'0'); 224 } 225 if(*evalp) 226 r = number(md, 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; 251 } 252 pat = runerealloc(pat, npat+1); 253 pat[npat++] = c; 254 } 255 out: 256 pat = runerealloc(pat, npat+1); 257 pat[npat] = 0; 258 if(*evalp) 259 r = regexp(md, t, lim, r, pat, dir, evalp); 260 free(pat); 261 dir = None; 262 size = Line; 263 break; 264 } 265 } 266 if(*evalp && dir != None) 267 r = number(md, t, r, 1, dir, Line, evalp); /* do previous one */ 268 *qp = q; 269 return r; 270 } 271