plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }