2003-12-11 17:50:28 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <draw.h>
|
|
|
|
#include <thread.h>
|
|
|
|
#include <cursor.h>
|
|
|
|
#include <mouse.h>
|
|
|
|
#include <keyboard.h>
|
|
|
|
#include <frame.h>
|
|
|
|
#include <fcall.h>
|
|
|
|
#include <plumb.h>
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
None = 0,
|
|
|
|
Fore = '+',
|
|
|
|
Back = '-',
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Char,
|
|
|
|
Line,
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
isaddrc(int r)
|
|
|
|
{
|
|
|
|
if(r && utfrune("0123456789+-/$.#,;", r)!=nil)
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* quite hard: could be almost anything but white space, but we are a little conservative,
|
|
|
|
* aiming for regular expressions of alphanumerics and no white space
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
isregexc(int r)
|
|
|
|
{
|
|
|
|
if(r == 0)
|
|
|
|
return FALSE;
|
|
|
|
if(isalnum(r))
|
|
|
|
return TRUE;
|
|
|
|
if(utfrune("^+-.*?#,;[]()$", r)!=nil)
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Range
|
2004-10-22 17:11:30 +00:00
|
|
|
number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
|
2003-12-11 17:50:28 +00:00
|
|
|
{
|
|
|
|
uint q0, q1;
|
|
|
|
|
|
|
|
if(size == Char){
|
|
|
|
if(dir == Fore)
|
|
|
|
line = r.q1+line;
|
|
|
|
else if(dir == Back){
|
|
|
|
if(r.q0==0 && line>0)
|
|
|
|
r.q0 = t->file->b.nc;
|
|
|
|
line = r.q0 - line;
|
|
|
|
}
|
|
|
|
if(line<0 || line>t->file->b.nc)
|
|
|
|
goto Rescue;
|
|
|
|
*evalp = TRUE;
|
2004-03-26 01:59:35 +00:00
|
|
|
return range(line, line);
|
2003-12-11 17:50:28 +00:00
|
|
|
}
|
|
|
|
q0 = r.q0;
|
|
|
|
q1 = r.q1;
|
|
|
|
switch(dir){
|
|
|
|
case None:
|
|
|
|
q0 = 0;
|
|
|
|
q1 = 0;
|
|
|
|
Forward:
|
|
|
|
while(line>0 && q1<t->file->b.nc)
|
|
|
|
if(textreadc(t, q1++) == '\n' || q1==t->file->b.nc)
|
|
|
|
if(--line > 0)
|
|
|
|
q0 = q1;
|
|
|
|
if(line > 0)
|
|
|
|
goto Rescue;
|
|
|
|
break;
|
|
|
|
case Fore:
|
|
|
|
if(q1 > 0)
|
2004-10-22 17:11:30 +00:00
|
|
|
while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
|
2003-12-11 17:50:28 +00:00
|
|
|
q1++;
|
|
|
|
q0 = q1;
|
|
|
|
goto Forward;
|
|
|
|
case Back:
|
|
|
|
if(q0 < t->file->b.nc)
|
|
|
|
while(q0>0 && textreadc(t, q0-1)!='\n')
|
|
|
|
q0--;
|
|
|
|
q1 = q0;
|
|
|
|
while(line>0 && q0>0){
|
|
|
|
if(textreadc(t, q0-1) == '\n'){
|
|
|
|
if(--line >= 0)
|
|
|
|
q1 = q0;
|
|
|
|
}
|
|
|
|
--q0;
|
|
|
|
}
|
|
|
|
if(line > 0)
|
|
|
|
goto Rescue;
|
|
|
|
while(q0>0 && textreadc(t, q0-1)!='\n')
|
|
|
|
--q0;
|
|
|
|
}
|
|
|
|
*evalp = TRUE;
|
2004-03-26 01:59:35 +00:00
|
|
|
return range(q0, q1);
|
2003-12-11 17:50:28 +00:00
|
|
|
|
|
|
|
Rescue:
|
2004-10-22 17:11:30 +00:00
|
|
|
if(showerr)
|
2003-12-11 17:50:28 +00:00
|
|
|
warning(nil, "address out of range\n");
|
|
|
|
*evalp = FALSE;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Range
|
2004-10-22 17:11:30 +00:00
|
|
|
regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
|
2003-12-11 17:50:28 +00:00
|
|
|
{
|
|
|
|
int found;
|
|
|
|
Rangeset sel;
|
|
|
|
int q;
|
|
|
|
|
|
|
|
if(pat[0] == '\0' && rxnull()){
|
2004-10-22 17:11:30 +00:00
|
|
|
if(showerr)
|
|
|
|
warning(nil, "no previous regular expression\n");
|
2003-12-11 17:50:28 +00:00
|
|
|
*foundp = FALSE;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if(pat[0] && rxcompile(pat) == FALSE){
|
|
|
|
*foundp = FALSE;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if(dir == Back)
|
|
|
|
found = rxbexecute(t, r.q0, &sel);
|
|
|
|
else{
|
|
|
|
if(lim.q0 < 0)
|
|
|
|
q = Infinity;
|
|
|
|
else
|
|
|
|
q = lim.q1;
|
|
|
|
found = rxexecute(t, nil, r.q1, q, &sel);
|
|
|
|
}
|
2004-10-22 17:11:30 +00:00
|
|
|
if(!found && showerr)
|
2003-12-11 17:50:28 +00:00
|
|
|
warning(nil, "no match for regexp\n");
|
|
|
|
*foundp = found;
|
|
|
|
return sel.r[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
Range
|
2004-10-22 17:11:30 +00:00
|
|
|
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
|
2003-12-11 17:50:28 +00:00
|
|
|
{
|
|
|
|
int dir, size, npat;
|
|
|
|
int prevc, c, nc, n;
|
|
|
|
uint q;
|
|
|
|
Rune *pat;
|
|
|
|
Range r, nr;
|
|
|
|
|
|
|
|
r = ar;
|
|
|
|
q = q0;
|
|
|
|
dir = None;
|
|
|
|
size = Line;
|
|
|
|
c = 0;
|
|
|
|
while(q < q1){
|
|
|
|
prevc = c;
|
|
|
|
c = (*getc)(a, q++);
|
|
|
|
switch(c){
|
|
|
|
default:
|
|
|
|
*qp = q-1;
|
|
|
|
return r;
|
|
|
|
case ';':
|
|
|
|
ar = r;
|
|
|
|
/* fall through */
|
|
|
|
case ',':
|
|
|
|
if(prevc == 0) /* lhs defaults to 0 */
|
|
|
|
r.q0 = 0;
|
|
|
|
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
|
|
|
|
r.q1 = t->file->b.nc;
|
|
|
|
else{
|
2004-10-22 17:11:30 +00:00
|
|
|
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
|
2003-12-11 17:50:28 +00:00
|
|
|
r.q1 = nr.q1;
|
|
|
|
}
|
|
|
|
*qp = q;
|
|
|
|
return r;
|
|
|
|
case '+':
|
|
|
|
case '-':
|
|
|
|
if(*evalp && (prevc=='+' || prevc=='-'))
|
|
|
|
if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
|
2004-10-22 17:11:30 +00:00
|
|
|
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
|
2003-12-11 17:50:28 +00:00
|
|
|
dir = c;
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
case '$':
|
|
|
|
if(q != q0+1){
|
|
|
|
*qp = q-1;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if(*evalp)
|
|
|
|
if(c == '.')
|
|
|
|
r = ar;
|
|
|
|
else
|
2004-03-26 01:59:35 +00:00
|
|
|
r = range(t->file->b.nc, t->file->b.nc);
|
2003-12-11 17:50:28 +00:00
|
|
|
if(q < q1)
|
|
|
|
dir = Fore;
|
|
|
|
else
|
|
|
|
dir = None;
|
|
|
|
break;
|
|
|
|
case '#':
|
|
|
|
if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
|
|
|
|
*qp = q-1;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
size = Char;
|
|
|
|
/* fall through */
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
n = c -'0';
|
|
|
|
while(q<q1){
|
|
|
|
c = (*getc)(a, q++);
|
|
|
|
if(c<'0' || '9'<c){
|
|
|
|
q--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n = n*10+(c-'0');
|
|
|
|
}
|
|
|
|
if(*evalp)
|
2004-10-22 17:11:30 +00:00
|
|
|
r = number(showerr, t, r, n, dir, size, evalp);
|
2003-12-11 17:50:28 +00:00
|
|
|
dir = None;
|
|
|
|
size = Line;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
dir = Back;
|
|
|
|
/* fall through */
|
|
|
|
case '/':
|
|
|
|
npat = 0;
|
|
|
|
pat = nil;
|
|
|
|
while(q<q1){
|
|
|
|
c = (*getc)(a, q++);
|
|
|
|
switch(c){
|
|
|
|
case '\n':
|
|
|
|
--q;
|
|
|
|
goto out;
|
|
|
|
case '\\':
|
|
|
|
pat = runerealloc(pat, npat+1);
|
|
|
|
pat[npat++] = c;
|
|
|
|
if(q == q1)
|
|
|
|
goto out;
|
|
|
|
c = (*getc)(a, q++);
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
pat = runerealloc(pat, npat+1);
|
|
|
|
pat[npat++] = c;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
pat = runerealloc(pat, npat+1);
|
|
|
|
pat[npat] = 0;
|
|
|
|
if(*evalp)
|
2004-10-22 17:11:30 +00:00
|
|
|
r = regexp(showerr, t, lim, r, pat, dir, evalp);
|
2003-12-11 17:50:28 +00:00
|
|
|
free(pat);
|
|
|
|
dir = None;
|
|
|
|
size = Line;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(*evalp && dir != None)
|
2004-10-22 17:11:30 +00:00
|
|
|
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
|
2003-12-11 17:50:28 +00:00
|
|
|
*qp = q;
|
|
|
|
return r;
|
|
|
|
}
|