addr.c (5547B)
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" 14 15 enum 16 { 17 None = 0, 18 Fore = '+', 19 Back = '-' 20 }; 21 22 enum 23 { 24 Char, 25 Line 26 }; 27 28 int 29 isaddrc(int r) 30 { 31 if(r && utfrune("0123456789+-/$.#,;?", r)!=nil) 32 return TRUE; 33 return FALSE; 34 } 35 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 } 51 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 } 72 73 Range 74 number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp) 75 { 76 uint q0, q1; 77 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; 122 } 123 --q0; 124 } 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; 130 } 131 *evalp = TRUE; 132 return range(q0, q1); 133 134 Rescue: 135 if(showerr) 136 warning(nil, "address out of range\n"); 137 *evalp = FALSE; 138 return r; 139 } 140 141 142 Range 143 regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp) 144 { 145 int found; 146 Rangeset sel; 147 int q; 148 149 if(pat[0] == '\0' && rxnull()){ 150 if(showerr) 151 warning(nil, "no previous regular expression\n"); 152 *foundp = FALSE; 153 return r; 154 } 155 if(pat[0] && rxcompile(pat) == FALSE){ 156 *foundp = FALSE; 157 return r; 158 } 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); 167 } 168 if(!found && showerr) 169 warning(nil, "no match for regexp\n"); 170 *foundp = found; 171 return sel.r[0]; 172 } 173 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, int reverse) 176 { 177 int dir, size, npat; 178 int prevc, c, nc, n; 179 uint q; 180 Rune *pat; 181 Range r, nr; 182 183 r = ar; 184 q = q0; 185 dir = None; 186 if(reverse) 187 dir = Back; 188 size = Line; 189 c = 0; 190 while(q < q1){ 191 prevc = c; 192 c = (*getc)(a, q++); 193 switch(c){ 194 default: 195 *qp = q-1; 196 return r; 197 case ';': 198 ar = r; 199 /* fall through */ 200 case ',': 201 if(prevc == 0) /* lhs defaults to 0 */ 202 r.q0 = 0; 203 if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */ 204 r.q1 = t->file->b.nc; 205 else{ 206 nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q, FALSE); 207 r.q1 = nr.q1; 208 } 209 *qp = q; 210 return r; 211 case '+': 212 case '-': 213 if(*evalp && (prevc=='+' || prevc=='-')) 214 if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?') 215 r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */ 216 dir = c; 217 break; 218 case '.': 219 case '$': 220 if(q != q0+1){ 221 *qp = q-1; 222 return r; 223 } 224 if(*evalp) 225 if(c == '.') 226 r = ar; 227 else 228 r = range(t->file->b.nc, t->file->b.nc); 229 if(q < q1) 230 dir = Fore; 231 else 232 dir = None; 233 break; 234 case '#': 235 if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){ 236 *qp = q-1; 237 return r; 238 } 239 size = Char; 240 /* fall through */ 241 case '0': case '1': case '2': case '3': case '4': 242 case '5': case '6': case '7': case '8': case '9': 243 n = c -'0'; 244 while(q<q1){ 245 nc = (*getc)(a, q++); 246 if(nc<'0' || '9'<nc){ 247 q--; 248 break; 249 } 250 n = n*10+(nc-'0'); 251 } 252 if(*evalp) 253 r = number(showerr, t, r, n, dir, size, evalp); 254 dir = None; 255 size = Line; 256 break; 257 case '?': 258 dir = Back; 259 /* fall through */ 260 case '/': 261 npat = 0; 262 pat = nil; 263 while(q<q1){ 264 c = (*getc)(a, q++); 265 switch(c){ 266 case '\n': 267 --q; 268 goto out; 269 case '\\': 270 pat = runerealloc(pat, npat+1); 271 pat[npat++] = c; 272 if(q == q1) 273 goto out; 274 c = (*getc)(a, q++); 275 break; 276 case '/': 277 goto out; 278 } 279 pat = runerealloc(pat, npat+1); 280 pat[npat++] = c; 281 } 282 out: 283 pat = runerealloc(pat, npat+1); 284 pat[npat] = 0; 285 if(*evalp) 286 r = regexp(showerr, t, lim, r, pat, dir, evalp); 287 free(pat); 288 dir = None; 289 size = Line; 290 break; 291 } 292 } 293 if(*evalp && dir != None) 294 r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */ 295 *qp = q; 296 return r; 297 }