Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "a.h"

/*
 * 16. Conditional acceptance of input.
 *
 *      conditions are
 *              c - condition letter (o, e, t, n)
 *              !c - not c
 *              N - N>0
 *              !N - N <= 0
 *              'a'b' - if a==b
 *              !'a'b'  - if a!=b
 *
 *      \{xxx\} can be used for newline in bodies
 *
 *      .if .ie .el
 *
 */

int iftrue[20];
int niftrue;

void
startbody(void)
{
        int c;
                        
        while((c = getrune()) == ' ' || c == '\t')
                ;
        ungetrune(c);
}

void
skipbody(void)
{
        int c, cc, nbrace;

        nbrace = 0;
        for(cc=0; (c = getrune()) >= 0; cc=c){
                if(c == '\n' && nbrace <= 0)
                        break;
                if(cc == '\\' && c == '{')
                        nbrace++;
                if(cc == '\\' && c == '}')
                        nbrace--;
        }
}

int
ifeval(void)
{
        int c, cc, neg, nc;
        Rune line[MaxLine], *p, *e, *q;
        Rune *a;
        
        while((c = getnext()) == ' ' || c == '\t')
                ;
        neg = 0;
        while(c == '!'){
                neg = !neg;
                c = getnext();
        }

        if('0' <= c && c <= '9'){
                ungetnext(c);
                a = copyarg();
                c = (eval(a)>0) ^ neg;
                free(a);
                return c;
        }
        
        switch(c){
        case ' ':
        case '\n':
                ungetnext(c);
                return !neg;
        case 'o':       /* odd page */
        case 't':       /* troff */
        case 'h':       /* htmlroff */
                while((c = getrune()) != ' ' && c != '\t' && c != '\n' && c >= 0)
                        ;
                return 1 ^ neg;
        case 'n':       /* nroff */
        case 'e':       /* even page */
                while((c = getnext()) != ' ' && c != '\t' && c != '\n' && c >= 0)
                        ;
                return 0 ^ neg;
        }

        /* string comparison 'string1'string2' */
        p = line;
        e = p+nelem(line);
        nc = 0;
        q = nil;
        while((cc=getnext()) >= 0 && cc != '\n' && p<e){
                if(cc == c){
                        if(++nc == 2)
                                break;
                        q = p;
                }
                *p++ = cc;
        }
        if(cc != c){
                ungetnext(cc);
                return 0;
        }
        if(nc < 2){
                return 0;
        }
        *p = 0;
        return (q-line == p-(q+1)
                && memcmp(line, q+1, (q-line)*sizeof(Rune))==0) ^ neg;
}
        
void
r_if(Rune *name)
{
        int n;
        
        n = ifeval();
        if(runestrcmp(name, L("ie")) == 0){
                if(niftrue >= nelem(iftrue))
                        sysfatal("%Cie overflow", dot);
                iftrue[niftrue++] = n;
        }
        if(n)
                startbody();
        else
                skipbody();
}

void
r_el(Rune *name)
{
        USED(name);
        
        if(niftrue <= 0){
                warn("%Cel underflow", dot);
                return;
        }
        if(iftrue[--niftrue])
                skipbody();
        else
                startbody();
}

void
t16init(void)
{
        addraw(L("if"), r_if);
        addraw(L("ie"), r_if);
        addraw(L("el"), r_el);
        
        addesc('{', e_nop, HtmlMode|ArgMode);
        addesc('}', e_nop, HtmlMode|ArgMode);
}