xref: /plan9/sys/src/cmd/acme/addr.c (revision d3907fe5a68251e8b016f54f72acf8767ba044bb)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier enum
157dd7cddfSDavid du Colombier {
167dd7cddfSDavid du Colombier 	None = 0,
177dd7cddfSDavid du Colombier 	Fore = '+',
187dd7cddfSDavid du Colombier 	Back = '-',
197dd7cddfSDavid du Colombier };
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier enum
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier 	Char,
247dd7cddfSDavid du Colombier 	Line,
257dd7cddfSDavid du Colombier };
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier int
isaddrc(int r)287dd7cddfSDavid du Colombier isaddrc(int r)
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 	if(r && utfrune("0123456789+-/$.#,;", r)!=nil)
317dd7cddfSDavid du Colombier 		return TRUE;
327dd7cddfSDavid du Colombier 	return FALSE;
337dd7cddfSDavid du Colombier }
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier /*
367dd7cddfSDavid du Colombier  * quite hard: could be almost anything but white space, but we are a little conservative,
377dd7cddfSDavid du Colombier  * aiming for regular expressions of alphanumerics and no white space
387dd7cddfSDavid du Colombier  */
397dd7cddfSDavid du Colombier int
isregexc(int r)407dd7cddfSDavid du Colombier isregexc(int r)
417dd7cddfSDavid du Colombier {
427dd7cddfSDavid du Colombier 	if(r == 0)
437dd7cddfSDavid du Colombier 		return FALSE;
447dd7cddfSDavid du Colombier 	if(isalnum(r))
457dd7cddfSDavid du Colombier 		return TRUE;
467dd7cddfSDavid du Colombier 	if(utfrune("^+-.*?#,;[]()$", r)!=nil)
477dd7cddfSDavid du Colombier 		return TRUE;
487dd7cddfSDavid du Colombier 	return FALSE;
497dd7cddfSDavid du Colombier }
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier Range
number(Mntdir * md,Text * t,Range r,int line,int dir,int size,int * evalp)5259cc4ca5SDavid du Colombier number(Mntdir *md, Text *t, Range r, int line, int dir, int size, int *evalp)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier 	uint q0, q1;
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier 	if(size == Char){
577dd7cddfSDavid du Colombier 		if(dir == Fore)
587dd7cddfSDavid du Colombier 			line = r.q1+line;
597dd7cddfSDavid du Colombier 		else if(dir == Back){
607dd7cddfSDavid du Colombier 			if(r.q0==0 && line>0)
617dd7cddfSDavid du Colombier 				r.q0 = t->file->nc;
627dd7cddfSDavid du Colombier 			line = r.q0 - line;
637dd7cddfSDavid du Colombier 		}
647dd7cddfSDavid du Colombier 		if(line<0 || line>t->file->nc)
657dd7cddfSDavid du Colombier 			goto Rescue;
667dd7cddfSDavid du Colombier 		*evalp = TRUE;
677dd7cddfSDavid du Colombier 		return (Range){line, line};
687dd7cddfSDavid du Colombier 	}
697dd7cddfSDavid du Colombier 	q0 = r.q0;
707dd7cddfSDavid du Colombier 	q1 = r.q1;
717dd7cddfSDavid du Colombier 	switch(dir){
727dd7cddfSDavid du Colombier 	case None:
737dd7cddfSDavid du Colombier 		q0 = 0;
747dd7cddfSDavid du Colombier 		q1 = 0;
757dd7cddfSDavid du Colombier 	Forward:
767dd7cddfSDavid du Colombier 		while(line>0 && q1<t->file->nc)
779a747e4fSDavid du Colombier 			if(textreadc(t, q1++) == '\n' || q1==t->file->nc)
787dd7cddfSDavid du Colombier 				if(--line > 0)
797dd7cddfSDavid du Colombier 					q0 = q1;
807dd7cddfSDavid du Colombier 		if(line > 0)
817dd7cddfSDavid du Colombier 			goto Rescue;
827dd7cddfSDavid du Colombier 		break;
837dd7cddfSDavid du Colombier 	case Fore:
847dd7cddfSDavid du Colombier 		if(q1 > 0)
85e7d29567SDavid du Colombier 			while(q1<t->file->nc && textreadc(t, q1-1) != '\n')
867dd7cddfSDavid du Colombier 				q1++;
877dd7cddfSDavid du Colombier 		q0 = q1;
887dd7cddfSDavid du Colombier 		goto Forward;
897dd7cddfSDavid du Colombier 	case Back:
907dd7cddfSDavid du Colombier 		if(q0 < t->file->nc)
917dd7cddfSDavid du Colombier 			while(q0>0 && textreadc(t, q0-1)!='\n')
927dd7cddfSDavid du Colombier 				q0--;
937dd7cddfSDavid du Colombier 		q1 = q0;
947dd7cddfSDavid du Colombier 		while(line>0 && q0>0){
957dd7cddfSDavid du Colombier 			if(textreadc(t, q0-1) == '\n'){
967dd7cddfSDavid du Colombier 				if(--line >= 0)
977dd7cddfSDavid du Colombier 					q1 = q0;
987dd7cddfSDavid du Colombier 			}
997dd7cddfSDavid du Colombier 			--q0;
1007dd7cddfSDavid du Colombier 		}
101*d3907fe5SDavid du Colombier 		/* :1-1 is :0 = #0, but :1-2 is an error */
102*d3907fe5SDavid du Colombier 		if(line > 1)
1037dd7cddfSDavid du Colombier 			goto Rescue;
1047dd7cddfSDavid du Colombier 		while(q0>0 && textreadc(t, q0-1)!='\n')
1057dd7cddfSDavid du Colombier 			--q0;
1067dd7cddfSDavid du Colombier 	}
1077dd7cddfSDavid du Colombier 	*evalp = TRUE;
1087dd7cddfSDavid du Colombier 	return (Range){q0, q1};
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier     Rescue:
11159cc4ca5SDavid du Colombier 	if(md != nil)
1127dd7cddfSDavid du Colombier 		warning(nil, "address out of range\n");
1137dd7cddfSDavid du Colombier 	*evalp = FALSE;
1147dd7cddfSDavid du Colombier 	return r;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier Range
regexp(Mntdir * md,Text * t,Range lim,Range r,Rune * pat,int dir,int * foundp)11959cc4ca5SDavid du Colombier regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier 	int found;
1227dd7cddfSDavid du Colombier 	Rangeset sel;
1237dd7cddfSDavid du Colombier 	int q;
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier 	if(pat[0] == '\0' && rxnull()){
12659cc4ca5SDavid du Colombier 		warning(md, "no previous regular expression\n");
1277dd7cddfSDavid du Colombier 		*foundp = FALSE;
1287dd7cddfSDavid du Colombier 		return r;
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier 	if(pat[0] && rxcompile(pat) == FALSE){
1317dd7cddfSDavid du Colombier 		*foundp = FALSE;
1327dd7cddfSDavid du Colombier 		return r;
1337dd7cddfSDavid du Colombier 	}
1347dd7cddfSDavid du Colombier 	if(dir == Back)
1357dd7cddfSDavid du Colombier 		found = rxbexecute(t, r.q0, &sel);
1367dd7cddfSDavid du Colombier 	else{
1377dd7cddfSDavid du Colombier 		if(lim.q0 < 0)
1387dd7cddfSDavid du Colombier 			q = Infinity;
1397dd7cddfSDavid du Colombier 		else
1407dd7cddfSDavid du Colombier 			q = lim.q1;
14159cc4ca5SDavid du Colombier 		found = rxexecute(t, nil, r.q1, q, &sel);
1427dd7cddfSDavid du Colombier 	}
14359cc4ca5SDavid du Colombier 	if(!found && md==nil)
1447dd7cddfSDavid du Colombier 		warning(nil, "no match for regexp\n");
1457dd7cddfSDavid du Colombier 	*foundp = found;
1467dd7cddfSDavid du Colombier 	return sel.r[0];
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier Range
address(Mntdir * md,Text * t,Range lim,Range ar,void * a,uint q0,uint q1,int (* getc)(void *,uint),int * evalp,uint * qp)15059cc4ca5SDavid du Colombier address(Mntdir *md, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint),  int *evalp, uint *qp)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier 	int dir, size, npat;
1539a747e4fSDavid du Colombier 	int prevc, c, nc, n;
1547dd7cddfSDavid du Colombier 	uint q;
1557dd7cddfSDavid du Colombier 	Rune *pat;
1567dd7cddfSDavid du Colombier 	Range r, nr;
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	r = ar;
1597dd7cddfSDavid du Colombier 	q = q0;
1607dd7cddfSDavid du Colombier 	dir = None;
1617dd7cddfSDavid du Colombier 	size = Line;
1627dd7cddfSDavid du Colombier 	c = 0;
1637dd7cddfSDavid du Colombier 	while(q < q1){
1647dd7cddfSDavid du Colombier 		prevc = c;
1657dd7cddfSDavid du Colombier 		c = (*getc)(a, q++);
1667dd7cddfSDavid du Colombier 		switch(c){
1677dd7cddfSDavid du Colombier 		default:
1687dd7cddfSDavid du Colombier 			*qp = q-1;
1697dd7cddfSDavid du Colombier 			return r;
1707dd7cddfSDavid du Colombier 		case ';':
1717dd7cddfSDavid du Colombier 			ar = r;
1727dd7cddfSDavid du Colombier 			/* fall through */
1737dd7cddfSDavid du Colombier 		case ',':
1747dd7cddfSDavid du Colombier 			if(prevc == 0)	/* lhs defaults to 0 */
1757dd7cddfSDavid du Colombier 				r.q0 = 0;
1767dd7cddfSDavid du Colombier 			if(q>=q1 && t!=nil && t->file!=nil)	/* rhs defaults to $ */
1777dd7cddfSDavid du Colombier 				r.q1 = t->file->nc;
1787dd7cddfSDavid du Colombier 			else{
17959cc4ca5SDavid du Colombier 				nr = address(md, t, lim, ar, a, q, q1, getc, evalp, &q);
1807dd7cddfSDavid du Colombier 				r.q1 = nr.q1;
1817dd7cddfSDavid du Colombier 			}
1827dd7cddfSDavid du Colombier 			*qp = q;
1837dd7cddfSDavid du Colombier 			return r;
1847dd7cddfSDavid du Colombier 		case '+':
1857dd7cddfSDavid du Colombier 		case '-':
1869a747e4fSDavid du Colombier 			if(*evalp && (prevc=='+' || prevc=='-'))
1879a747e4fSDavid du Colombier 				if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
18859cc4ca5SDavid du Colombier 					r = number(md, t, r, 1, prevc, Line, evalp);	/* do previous one */
1897dd7cddfSDavid du Colombier 			dir = c;
1907dd7cddfSDavid du Colombier 			break;
1917dd7cddfSDavid du Colombier 		case '.':
1927dd7cddfSDavid du Colombier 		case '$':
1937dd7cddfSDavid du Colombier 			if(q != q0+1){
1947dd7cddfSDavid du Colombier 				*qp = q-1;
1957dd7cddfSDavid du Colombier 				return r;
1967dd7cddfSDavid du Colombier 			}
1977dd7cddfSDavid du Colombier 			if(*evalp)
1987dd7cddfSDavid du Colombier 				if(c == '.')
1997dd7cddfSDavid du Colombier 					r = ar;
2007dd7cddfSDavid du Colombier 				else
2017dd7cddfSDavid du Colombier 					r = (Range){t->file->nc, t->file->nc};
2027dd7cddfSDavid du Colombier 			if(q < q1)
2037dd7cddfSDavid du Colombier 				dir = Fore;
2047dd7cddfSDavid du Colombier 			else
2057dd7cddfSDavid du Colombier 				dir = None;
2067dd7cddfSDavid du Colombier 			break;
2077dd7cddfSDavid du Colombier 		case '#':
2087dd7cddfSDavid du Colombier 			if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
2097dd7cddfSDavid du Colombier 				*qp = q-1;
2107dd7cddfSDavid du Colombier 				return r;
2117dd7cddfSDavid du Colombier 			}
2127dd7cddfSDavid du Colombier 			size = Char;
2137dd7cddfSDavid du Colombier 			/* fall through */
2147dd7cddfSDavid du Colombier 		case '0': case '1': case '2': case '3': case '4':
2157dd7cddfSDavid du Colombier 		case '5': case '6': case '7': case '8': case '9':
2167dd7cddfSDavid du Colombier 			n = c -'0';
2177dd7cddfSDavid du Colombier 			while(q<q1){
2187dd7cddfSDavid du Colombier 				c = (*getc)(a, q++);
2197dd7cddfSDavid du Colombier 				if(c<'0' || '9'<c){
2207dd7cddfSDavid du Colombier 					q--;
2217dd7cddfSDavid du Colombier 					break;
2227dd7cddfSDavid du Colombier 				}
2237dd7cddfSDavid du Colombier 				n = n*10+(c-'0');
2247dd7cddfSDavid du Colombier 			}
2257dd7cddfSDavid du Colombier 			if(*evalp)
22659cc4ca5SDavid du Colombier 				r = number(md, t, r, n, dir, size, evalp);
2277dd7cddfSDavid du Colombier 			dir = None;
2287dd7cddfSDavid du Colombier 			size = Line;
2297dd7cddfSDavid du Colombier 			break;
2309a747e4fSDavid du Colombier 		case '?':
2319a747e4fSDavid du Colombier 			dir = Back;
2329a747e4fSDavid du Colombier 			/* fall through */
2337dd7cddfSDavid du Colombier 		case '/':
2347dd7cddfSDavid du Colombier 			npat = 0;
2357dd7cddfSDavid du Colombier 			pat = nil;
2367dd7cddfSDavid du Colombier 			while(q<q1){
2377dd7cddfSDavid du Colombier 				c = (*getc)(a, q++);
2387dd7cddfSDavid du Colombier 				switch(c){
2397dd7cddfSDavid du Colombier 				case '\n':
2407dd7cddfSDavid du Colombier 					--q;
2417dd7cddfSDavid du Colombier 					goto out;
2427dd7cddfSDavid du Colombier 				case '\\':
2437dd7cddfSDavid du Colombier 					pat = runerealloc(pat, npat+1);
2447dd7cddfSDavid du Colombier 					pat[npat++] = c;
2457dd7cddfSDavid du Colombier 					if(q == q1)
2467dd7cddfSDavid du Colombier 						goto out;
2477dd7cddfSDavid du Colombier 					c = (*getc)(a, q++);
2487dd7cddfSDavid du Colombier 					break;
2497dd7cddfSDavid du Colombier 				case '/':
2507dd7cddfSDavid du Colombier 					goto out;
2517dd7cddfSDavid du Colombier 				}
2527dd7cddfSDavid du Colombier 				pat = runerealloc(pat, npat+1);
2537dd7cddfSDavid du Colombier 				pat[npat++] = c;
2547dd7cddfSDavid du Colombier 			}
2557dd7cddfSDavid du Colombier 		    out:
2567dd7cddfSDavid du Colombier 			pat = runerealloc(pat, npat+1);
2577dd7cddfSDavid du Colombier 			pat[npat] = 0;
2587dd7cddfSDavid du Colombier 			if(*evalp)
25959cc4ca5SDavid du Colombier 				r = regexp(md, t, lim, r, pat, dir, evalp);
2607dd7cddfSDavid du Colombier 			free(pat);
2617dd7cddfSDavid du Colombier 			dir = None;
2627dd7cddfSDavid du Colombier 			size = Line;
2637dd7cddfSDavid du Colombier 			break;
2647dd7cddfSDavid du Colombier 		}
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 	if(*evalp && dir != None)
26759cc4ca5SDavid du Colombier 		r = number(md, t, r, 1, dir, Line, evalp);	/* do previous one */
2687dd7cddfSDavid du Colombier 	*qp = q;
2697dd7cddfSDavid du Colombier 	return r;
2707dd7cddfSDavid du Colombier }
271