1 #include "a.h"
2 
3 /*
4  * 16. Conditional acceptance of input.
5  *
6  *	conditions are
7  *		c - condition letter (o, e, t, n)
8  *		!c - not c
9  *		N - N>0
10  *		!N - N <= 0
11  *		'a'b' - if a==b
12  *		!'a'b'	- if a!=b
13  *
14  *	\{xxx\} can be used for newline in bodies
15  *
16  *	.if .ie .el
17  *
18  */
19 
20 int iftrue[20];
21 int niftrue;
22 
23 void
startbody(void)24 startbody(void)
25 {
26 	int c;
27 
28 	while((c = getrune()) == ' ' || c == '\t')
29 		;
30 	ungetrune(c);
31 }
32 
33 void
skipbody(void)34 skipbody(void)
35 {
36 	int c, cc, nbrace;
37 
38 	nbrace = 0;
39 	for(cc=0; (c = getrune()) >= 0; cc=c){
40 		if(c == '\n' && nbrace <= 0)
41 			break;
42 		if(cc == '\\' && c == '{')
43 			nbrace++;
44 		if(cc == '\\' && c == '}')
45 			nbrace--;
46 	}
47 }
48 
49 int
ifeval(void)50 ifeval(void)
51 {
52 	int c, cc, neg, nc;
53 	Rune line[MaxLine], *p, *e, *q;
54 	Rune *a;
55 
56 	while((c = getnext()) == ' ' || c == '\t')
57 		;
58 	neg = 0;
59 	while(c == '!'){
60 		neg = !neg;
61 		c = getnext();
62 	}
63 
64 	if('0' <= c && c <= '9'){
65 		ungetnext(c);
66 		a = copyarg();
67 		c = (eval(a)>0) ^ neg;
68 		free(a);
69 		return c;
70 	}
71 
72 	switch(c){
73 	case ' ':
74 	case '\n':
75 		ungetnext(c);
76 		return !neg;
77 	case 'o':	/* odd page */
78 	case 't':	/* troff */
79 	case 'h':	/* htmlroff */
80 		while((c = getrune()) != ' ' && c != '\t' && c != '\n' && c >= 0)
81 			;
82 		return 1 ^ neg;
83 	case 'n':	/* nroff */
84 	case 'e':	/* even page */
85 		while((c = getnext()) != ' ' && c != '\t' && c != '\n' && c >= 0)
86 			;
87 		return 0 ^ neg;
88 	}
89 
90 	/* string comparison 'string1'string2' */
91 	p = line;
92 	e = p+nelem(line);
93 	nc = 0;
94 	q = nil;
95 	while((cc=getnext()) >= 0 && cc != '\n' && p<e){
96 		if(cc == c){
97 			if(++nc == 2)
98 				break;
99 			q = p;
100 		}
101 		*p++ = cc;
102 	}
103 	if(cc != c){
104 		ungetnext(cc);
105 		return 0;
106 	}
107 	if(nc < 2){
108 		return 0;
109 	}
110 	*p = 0;
111 	return (q-line == p-(q+1)
112 		&& memcmp(line, q+1, (q-line)*sizeof(Rune))==0) ^ neg;
113 }
114 
115 void
r_if(Rune * name)116 r_if(Rune *name)
117 {
118 	int n;
119 
120 	n = ifeval();
121 	if(runestrcmp(name, L("ie")) == 0){
122 		if(niftrue >= nelem(iftrue))
123 			sysfatal("%Cie overflow", dot);
124 		iftrue[niftrue++] = n;
125 	}
126 	if(n)
127 		startbody();
128 	else
129 		skipbody();
130 }
131 
132 void
r_el(Rune * name)133 r_el(Rune *name)
134 {
135 	USED(name);
136 
137 	if(niftrue <= 0){
138 		warn("%Cel underflow", dot);
139 		return;
140 	}
141 	if(iftrue[--niftrue])
142 		skipbody();
143 	else
144 		startbody();
145 }
146 
147 void
t16init(void)148 t16init(void)
149 {
150 	addraw(L("if"), r_if);
151 	addraw(L("ie"), r_if);
152 	addraw(L("el"), r_el);
153 
154 	addesc('{', e_nop, HtmlMode|ArgMode);
155 	addesc('}', e_nop, HtmlMode|ArgMode);
156 }
157