Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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;
}