shithub: riscv

ref: 45f7b30244297a8bf87789793eec875246ed063c
dir: /sys/src/cmd/htmlroff/t16.c/

View raw version
#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);
}