blob: f09688dc61526d3adfd949531fe6c1a2bff8e98c [file] [log] [blame]
#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
number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
{
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;
return range(line, line);
}
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==1 && q1==t->file->b.nc) // 6 goes to end of 5-line file
break;
if(line > 0)
goto Rescue;
break;
case Fore:
if(q1 > 0)
while(q1<t->file->b.nc && textreadc(t, q1-1) != '\n')
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;
}
/* :1-1 is :0 = #0, but :1-2 is an error */
if(line > 1)
goto Rescue;
while(q0>0 && textreadc(t, q0-1)!='\n')
--q0;
}
*evalp = TRUE;
return range(q0, q1);
Rescue:
if(showerr)
warning(nil, "address out of range\n");
*evalp = FALSE;
return r;
}
Range
regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
{
int found;
Rangeset sel;
int q;
if(pat[0] == '\0' && rxnull()){
if(showerr)
warning(nil, "no previous regular expression\n");
*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);
}
if(!found && showerr)
warning(nil, "no match for regexp\n");
*foundp = found;
return sel.r[0];
}
Range
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
{
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{
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
r.q1 = nr.q1;
}
*qp = q;
return r;
case '+':
case '-':
if(*evalp && (prevc=='+' || prevc=='-'))
if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
r = number(showerr, t, r, 1, prevc, Line, evalp); /* do previous one */
dir = c;
break;
case '.':
case '$':
if(q != q0+1){
*qp = q-1;
return r;
}
if(*evalp)
if(c == '.')
r = ar;
else
r = range(t->file->b.nc, t->file->b.nc);
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)
r = number(showerr, t, r, n, dir, size, evalp);
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)
r = regexp(showerr, t, lim, r, pat, dir, evalp);
free(pat);
dir = None;
size = Line;
break;
}
}
if(*evalp && dir != None)
r = number(showerr, t, r, 1, dir, Line, evalp); /* do previous one */
*qp = q;
return r;
}