TIVI-153: add as dependency for iputils
[profile/ivi/xmlto.git] / xmlif / xmlif.l
1 %{
2 /*
3  * xmlif -- support processing instructions for XML conditionalization
4  *
5  * By Eric S. Raymond <esr@thyrsus.com>, 3 Nov 1997 (as sgmlpre)
6  * Enhanced for XML September 2002, Licensed under GPLv2+ since 03/2009
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Filter XML according to conditionalizing markup.  Argument/value
22  * pairs from the command line are matched against the attributes of
23  * <?xmlif if> and <?xmlif elif> tags.  Spans between <?xmlif if> or
24  * <?xmlif elif> and the next conditional processing instruction are
25  * passed through unaltered if there is no attribute mismatch; spans
26  * between <?xmlif if not> and <?xmlif elif not> are passed if there
27  * is at least one attribute mismatch.  An attribute mismatch happens
28  * if an attribute occurs in both the command-line arguments and the
29  * tag, but the values do not match.  <?xmlif else> inverts the sense
30  * of the current comparison. Value matching is by string equality,
31  * except that "|" is interpreted as an alternation character.
32  * <?xmlif if>, <?xmlif fi>, <?xmlif else> and <?xmlif elif>, and will
33  * all be removed from the output.
34  *
35  * This lexer requires flex.  Limitations; attributes and values may be
36  * only 16384 (YY_BUF_SIZE) characters long.
37  */
38 #include <string.h>
39 #include <stdlib.h>
40
41 #define TRUE    1
42 #define FALSE   0
43
44 static char **selections;       /* selection tokens */
45 static int nselections;         /* number of selections */
46 static ifsense;                 /* sense of last `if' or unless seen */
47 static char *attribute;         /* last attribute scanned */
48
49 struct stack_t {
50     int                 matched;        /* matched at current level */
51     int                 suppressed;    /* suppressed branch? */
52     struct stack_t      *up;
53 };
54 static struct stack_t head, *end = &head;
55
56 static void push_level(void)
57 /* create activation record for the current level */
58 {
59     struct stack_t *newelt;
60
61 #ifdef DEBUG
62     fprintf(stderr, "{push_level()}");
63 #endif /* DEBUG */
64     newelt = (struct stack_t *)malloc(sizeof(struct stack_t));
65     newelt->up = end;
66     end = newelt;
67
68     end->matched = 0;
69     end->suppressed = end->up->suppressed;
70 }
71
72 static void pop_level(void)
73 /* delete activation record for the current level */
74 {
75     struct stack_t *up = end->up;
76
77 #ifdef DEBUG
78     fprintf(stderr, "{pop_level()}");
79 #endif /* DEBUG */
80     if (end != &head)
81     {
82         free(end);
83         end = up;
84     }
85 }
86
87 static void stash_attribute(char *attr)
88 /* stash an attribute away for comparison */
89 {
90 #ifdef DEBUG
91     fprintf(stderr, "{stash_attribute(%s)}", attr);
92 #endif /* DEBUG */
93     attribute = strdup(attr);
94 }
95
96 static void end_attribute(void)
97 /* we've seen all the attributes of a conditional, process them now */
98 {
99     struct stack_t      *up;
100
101     if (attribute)
102         free(attribute);
103     end->suppressed = (ifsense == !!end->suppressed);
104     for (up = end->up; up->up; up = up->up)
105         if (up->suppressed)
106         {
107             end->suppressed = 1;
108             break;
109         }
110     if (!end->matched && !end->suppressed)
111         end->matched = 1;
112 #ifdef DEBUG
113     fprintf(stderr,"{end_attribute(ifsense=%d)->%d}", ifsense, end->suppressed);
114 #endif /* DEBUG */
115 }
116
117 static int value_match(char *value, char *against)
118 /* return TRUE if values match (handles alternation syntax) */
119 {
120     char *vp, *ap;
121     int vn, an;
122
123 #ifdef DEBUG
124     fprintf(stderr, "{value_match(%s, %s)}", value, against);
125 #endif /* DEBUG */
126
127     for (vp = value; *vp; vp += vn)
128     {
129         vn = strcspn(vp, "|");
130         for (ap = against; *ap; ap += an)
131         {
132             an = strcspn(ap, "|");
133             if (an == vn && memcmp(ap, vp, an) == 0)
134                 return(TRUE);
135             if (ap[an] == '|')
136                 an++;
137         }
138         if (vp[vn] == '|')
139             vn++;
140     }
141
142     return(FALSE);
143 }
144
145 static int suppress(char *attr, char *value)
146 /* does a given attribute/value pair enable inclusion? */
147 {
148     int i;
149     int res;
150
151     for (i = 0; i < nselections; i++)
152     {
153         int eqoffset = strcspn(selections[i], "=");
154
155         if (strncasecmp(selections[i], attr, eqoffset) == 0)
156         {
157             /* attribute matches; enable (0) or lock in suppression (-1) */
158             res = value_match(value, selections[i] + eqoffset + 1) ? 0 : -1;
159             goto breakout;
160         }
161     }
162
163     res = 1;    /* no match -- suppress but don't lock it in */
164  breakout:
165 #ifdef DEBUG
166     fprintf(stderr, "{suppress(%s, %s)->%d}", attr, value, res);
167 #endif /* DEBUG */
168     return(res);
169 }
170
171 static void process_value(char *val)
172 /* process value in context of stashed attribute */
173 {
174     /* if pred has been set to -1 by a mismatch, latch it there */
175     if (end->suppressed > -1)
176         end->suppressed = suppress(attribute, val);
177 }
178
179 static void process_else()
180 /* process <?xmlif else> tag */
181 {
182     end->suppressed = end->matched;
183 #ifdef DEBUG
184     fprintf(stderr, "{else -> %d}", end->suppressed);
185 #endif /* DEBUG */
186 }
187
188
189 %}
190
191 ATTRIBUTE       [a-z][a-z0-9]*
192 DSTRING         \"[^"]*\"
193 SSTRING         \'[^']*\'
194 WS              [ \t\n]*
195
196 %x attrib val
197
198 %option batch never-interactive fast 8bit
199
200 %%
201 <INITIAL>\<\?xmlif{WS}if{WS}not{WS}     {BEGIN(attrib); ifsense = FALSE; push_level();}
202 <INITIAL>\<\?xmlif{WS}if{WS}            {BEGIN(attrib); ifsense = TRUE;  push_level();}
203 <INITIAL>\<\?xmlif{WS}elif{WS}not{WS}   {BEGIN(attrib); ifsense = FALSE;}
204 <INITIAL>\<\?xmlif{WS}elif{WS}          {BEGIN(attrib); ifsense = TRUE;}
205 <INITIAL>\<\?xmlif{WS}else\?>           {process_else();}
206
207 <INITIAL><\?xmlif{WS}fi\?>              {pop_level();}
208
209 <attrib>{ATTRIBUTE}             {stash_attribute(yytext);}
210 <attrib>=                       {BEGIN(val);}
211 <attrib>\?\>                    {BEGIN(INITIAL); end_attribute();}
212 <val>{DSTRING}|{SSTRING}        {
213                                     yytext[strlen(yytext)-1]='\0';
214                                     process_value(yytext+1);
215                                     BEGIN(attrib);
216                                 }
217 <val>\?\>                               {
218                                     fprintf(stderr,
219                                         "xmlif: > where value expected\n");
220                                     exit(1);
221                                 }
222
223 <INITIAL>.                      {
224                                     if (!end->suppressed)
225                                         putchar(yytext[0]);
226                                 }
227
228 %%
229 #include <string.h>
230
231 #include "config.h"
232
233 int yywrap() {exit(0);};
234
235 main(int argc, char *argv[])
236 {
237     int i;
238
239     selections = argv + 1;
240     nselections = argc - 1;
241
242     for (i = 0; i < nselections; i++)
243         if (strchr(selections[i], '=') == 0)
244         {
245             if (!strcmp(selections[i], "--help"))
246             {
247                 printf ("usage: xmlif attrib=value..\n");
248                 exit(0);
249             }
250
251             if (!strcmp(selections[i], "--version"))
252             {
253                 printf ("xmlif - xmlto version %s\n", VERSION);
254                 exit(0);
255             }
256
257             fprintf(stderr, "xmlif: malformed argument %d\n", i);
258             exit(1);
259         }
260
261     yylex();
262 }
263
264 /*
265  The following sets edit modes for GNU EMACS
266  Local Variables:
267  mode:c
268  case-fold-search:nil
269  End:
270 */
271 /* xmlif.l ends here */