123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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(Mntdir *md, 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->nc;
- line = r.q0 - line;
- }
- if(line<0 || line>t->file->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->nc)
- if(textreadc(t, q1++) == '\n' || q1==t->file->nc)
- if(--line > 0)
- q0 = q1;
- if(line > 0)
- goto Rescue;
- break;
- case Fore:
- if(q1 > 0)
- while(q1<t->file->nc && textreadc(t, q1-1) != '\n')
- q1++;
- q0 = q1;
- goto Forward;
- case Back:
- if(q0 < t->file->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(md != nil)
- warning(nil, "address out of range\n");
- *evalp = FALSE;
- return r;
- }
- Range
- regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
- {
- int found;
- Rangeset sel;
- int q;
- if(pat[0] == '\0' && rxnull()){
- warning(md, "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 && md==nil)
- warning(nil, "no match for regexp\n");
- *foundp = found;
- return sel.r[0];
- }
- Range
- address(Mntdir *md, 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->nc;
- else{
- nr = address(md, 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(md, 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->nc, t->file->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(md, 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(md, t, lim, r, pat, dir, evalp);
- free(pat);
- dir = None;
- size = Line;
- break;
- }
- }
- if(*evalp && dir != None)
- r = number(md, t, r, 1, dir, Line, evalp); /* do previous one */
- *qp = q;
- return r;
- }
|