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